1

В моем корневом каталоге у меня есть несколько папок с именами, такими как AA , BB , CC и т.д., Каждая из которых содержит файлы в формате AA1001.txt , BB1002.txt и т.д. В моей корневой папке у меня также есть файл all_to_delete который имеет куча имен файлов, разделенных символом новой строки, таким образом, выглядит примерно так:

AA1004.txt

BB3004.txt

BB3005.txt ...

Теперь я хочу просмотреть все подкаталоги в моем корневом каталоге и удалить все файлы, которые соответствуют указанному имени файла. До сих пор я пробовал что-то вроде:

while read line; do find . -type f -name $line -exec rm -f {} \;; done хотя, это не может работать, как уже while read line; do find . -type f -name $line; done не соответствует ни одному файлу (так как find выдает его как ./AA/AA1001.txt ...)

Ребята, у вас есть решение для меня?

3 ответа3

1

Насколько буквально ваше описание вашей проблемы?  Названия каталогов - все два символа?  Будет ли файл BB3004.txt всегда находиться в каталоге BB?  Если да, то вам не нужно find ; просто извлеките имя каталога из первых двух символов имени файла:

while read -r line
do
    dir=$(expr "$line" : '\(..\)')
    echo rm "$dir/$line"
    rm "$dir/$line"
done < all_to_delete
1

Есть много разных способов сделать это, но вот как я это сделаю:

Создан тестовый каталог с несколькими файлами в нем:

% ls ./teste
lala  lele  lolo  lulu

Создан файл со списком тех, которые я хотел бы удалить:

% cat to_delete.txt 
lele
lolo
lulu

Здесь я делаю цикл по каждой строке файла 'to_delete.txt', передавая имя файла команде find и затем, наконец, удаляя их:

% while read filename; do find ./teste -name ${filename} -print0 | xargs -0 rm -vf; done < to_delete.txt 
removed `./teste/lele'
removed `./teste/lolo'
removed `./teste/lulu'

Готово:

% ls ./teste                                                                                      
lala
1

При наличии файла с именами файлов проще всего будет прочитать его построчно и передать его для find . Однако это приведет к отдельному экземпляру find для каждого имени файла и может стать очень медленным для больших списков файлов и многих файлов в дереве каталогов.

Вместо этого я бы сделал что-то вроде этого:

find . -type f -name "*txt" | grep -wFf to_delete.txt | xargs -I{} rm '{}'

Хитрость заключается в том, чтобы дать grep ваш файл в виде списка шаблонов для поиска (-f). -F гарантирует, что ваши имена файлов обрабатываются как строки, а не как регулярные выражения, таким образом, ваши имена файлов могут содержать специальные символы, такие как * или [ или | , Затем вы переходите к xargs и используете кавычки '{}' , в противном случае произойдет сбой при удалении файлов.

ПРИМЕЧАНИЕ . Это предполагает, что все имена ваших файлов уникальны, что одно имя не может содержаться в другом. Например, у вас нет файлов с foo и foobar . Если вы сделаете это, учитывая шаблон foo , это удалит оба файла. Чтобы избежать этого использования:

while IFS= read -r line; do find . -name "$line" -delete; done < to_delete.txt 

От man find:

   -delete
          Delete files; true if removal succeeded. 

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .