Подтвердить что ты не робот

Rm не удаляет файлы по шаблону из script, но работает из командной строки

У меня возникла действительно глупая проблема с оболочкой Linux script. Я хочу удалить все файлы с расширением ".bz2" в каталоге. В script я вызываю

rm "$archivedir/*.bz2"

где $archivedir - путь к каталогу. Должно быть довольно просто, не так ли? Как-то он справляется с этой ошибкой:

rm: cannot remove `/var/archives/monthly/April/*.bz2': No such file or directory

Но есть файл в этом каталоге test.bz2, и если я изменю свой script на

echo rm "$archivedir/*.bz2"

и скопируйте/вставьте вывод этой строки в окно терминала, файл удаляется успешно. Что я делаю неправильно?

4b9b3361

Ответ 1

TL; DR

Цитата только переменная, а не весь ожидаемый путь с подстановочным знаком

rm "$archivedir"/*.bz2

Объяснение

  • В Unix программы обычно не интерпретируют подстановочные знаки. Оболочка интерпретирует незакодированные подстановочные знаки и заменяет каждый аргумент подстановки списком совпадающих имен файлов. если $archivedir может содержать пробелы, то rm $archivedir/*.bz2 может не делать то, что вы

  • Вы можете отключить этот процесс, указав символ подстановки, используя двойные или одинарные кавычки или обратную косую черту перед ним. Тем не менее, это не то, что вы хотите здесь, - вы хотите, чтобы подстановочный знак расширялся до списка файлов, которые он соответствует.

  • Будьте осторожны с написанием rm $archivedir/*.bz2 (без кавычек). Разделение слова (т.е. Разбиение командной строки на аргументы) происходит после замены $archivedir. Поэтому, если $archivedir содержит пробелы, тогда вы получите дополнительные аргументы, которые вы не намеревались. Скажем, archivedir /var/archives/monthly/April to June. Затем вы получите эквивалент записи rm /var/archives/monthly/April to June/*.bz2, который пытается удалить файлы "/var/archives/month/April", "to" и все файлы, соответствующие "June/*.bz2", который не является что вы хотите.

Правильное решение - написать:

rm "$archivedir"/*.bz2

Ответ 2

Просто, чтобы немного расшириться, bash имеет довольно сложные правила для работы с метасимволами в кавычках. В общем

  • почти ничего не интерпретируется в одинарных кавычках:

     echo '$foo/*.c'                  => $foo/*.c
     echo '\\*'                       => \\*
    
  • замена оболочки выполняется внутри двойных кавычек, но метасимволы файлов не разворачиваются:

     FOO=hello; echo "$foo/*.c"       => hello/*.c
    
  • все внутри backquotes передается на подоболочку, которая их интерпретирует. Переменная оболочки, которая не экспортируется, не определяется в подоболочке. Итак, первая команда эхо-пустая, но второе и третье эхо "bye":

    BAR=bye echo `echo $BAR`
    BAR=bye; echo `echo $BAR`
    export BAR=bye; echo `echo $BAR`
    

(И получить это, чтобы напечатать, как вы хотите, в SO выполняется несколько попыток, по-видимому, невозможно...)

Ответ 3

Исходная строка

rm "$archivedir/*.bz2"

Можно переписать как

rm "$archivedir"/*.bz2

для достижения такого же эффекта. Расширение подстановки не выполняется должным образом в вашей существующей настройке. Перемещая двойную кавычку к "фронту" пути к файлу (что является законным), вы избегаете этого.

Ответ 4

Кавычки заставляют строку интерпретироваться как строковый литерал, попробуйте удалить их.

Ответ 5

Я видел похожие ошибки при вызове оболочки script как ./shell_script.sh  из другой оболочки script. Это можно исправить, вызвав его как sh shell_script.sh

Ответ 6

Почему не просто rm -rf */*.bz2? Работает для меня на OSX.

Ответ 7

Дополнительная информация о внутренней работе: попробуйте ввести:

echo "$archivedir/*.bz2"

в командной строке оболочки. Вы увидите, что он сразу расширяется. Так что rm никогда не видит *; вместо этого это тот список, который передается ему.

Изменить: я вижу, вы в основном пробовали это. Что вы хотите сделать, попробуйте, когда в этом каталоге есть несколько файлов bz2. Затем вы увидите эффект.