Команда типа этой:
find /directory -type f -name "*.txt" -print | xargs rm
удалить все .txt
файлы в каталоге и подкаталогах, и это нормально. Но, если мы создадим переменную или массив для расширения файла, а затем поместим find
, например,
TXT=(*.txt)
for ii in ${TXT[@]}; do
find /directory -type f -name $TXT -print | xargs rm
done
эти команды не удаляют .txt
файлы в подкаталогах. Почему? Как изменить этот второй код, чтобы удалять файлы в подкаталогах?
PS: Я использовал массив, так как у меня несколько расширений файлов.
решение1
Ваше назначение массива,
TXT=(*.txt)
расширит *.txt
шаблон до списка имен файлов в текущем каталоге, которые соответствуют этому шаблону. Оболочка сделает это во время назначения. Это не то, что вам нужно. Вы хотите задать find
литеральную строку *.txt
, например:
pattern='*.txt'
find /directory -type f -name "$pattern" -exec rm {} +
Здесь я также избавился от xargs rm
и вместо этого выполняю rm
напрямую из find
. Большинство текущих реализаций find
могли бы использовать нестандартный -delete
вместо -exec rm {} +
:
pattern='*.txt'
find /directory -type f -name "$pattern" -delete
Обратите внимание, что здесь нет необходимости в цикле, поскольку мы имеем дело только с одним шаблоном. Также обратите внимание, что кавычки "$pattern"
в вызове find
важны, иначе шаблон будет заменен всеми соответствующими именами файлов в текущем каталоге перед find
запуском.
Для нескольких шаблонов можно сделать такой цикл:
patterns=( '*.txt' '*.tmp' )
for pattern in "${patterns[@]}"; do
find /directory -type f -name "$pattern" -delete
done
Кавычки в назначении массива необходимы, поскольку они не позволяют оболочке использовать шаблоны в качестве шаблонов подстановки имен файлов. Кавычки "${patterns[@]}"
и "$pattern"
также важны по той же причине.
Другой подход — сделать только один вызов find
, даже если у вас есть несколько шаблонов. Это немного ускорит работу, если /directory
это большая иерархия каталогов. Следующий код делает это, создавая массив -name
тестов для find
использования:
patterns=( '*.txt' '*.tmp' )
name_tests=( )
for pattern in "${patterns[@]}"; do
name_tests+=( -o -name "$pattern" )
done
# "${name_tests[@]:1}" removes the initial "-o", which shouldn't be there.
name_tests=( '(' "${name_tests[@]:1}" ')' )
find /directory -type f "${name_tests[@]}" -delete
В приведенном выше скрипте фактическая команда, выполняемая в конце, будет следующей:
find /directory -type f '(' -name '*.txt' -o -name '*.tmp' ')' -delete
... который удалит все обычные файлы, имеющие суффиксы в именах файлов.txt
или .tmp
в любом месте каталога или ниже /directory
.