rm не удается удалить файлы с помощью подстановочного знака из сценария, но работает из командной строки


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

rm "$archivedir/*.bz2"

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

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

а там и файл в этом каталоге называется test. bz2 и если я изменю свой скрипт на

echo rm "$archivedir/*.bz2"

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

6 52

6 ответов:

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/monthly/April", "to" и все файлы, соответствующие "June/*. bz2", что не то, что вы хотите.

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

rm "$archivedir"/*.bz2

Ваша исходная строка

rm "$archivedir/*.bz2"

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

rm "$archivedir"/*.bz2

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

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

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

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

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

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

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

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

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

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