Unix: как удалить файлы, перечисленные в файле


92

У меня есть длинный текстовый файл со списком масок файлов, которые я хочу удалить

Пример:

/tmp/aaa.jpg
/var/www1/*
/var/www/qwerty.php

Мне нужно их удалить. Пробовал rm `cat 1.txt`, и он говорит, что список слишком длинный.

Нашел эту команду, но когда я проверяю папки из списка, в некоторых из них все еще есть файлы. xargs rm <1.txtРучной вызов rm удаляет файлы из таких папок, поэтому нет проблем с разрешениями.


8
Несмотря на то, что прошло шесть лет: не могли бы вы принять один из ответов? Это пометит вопрос как решенный и поможет другим пользователям.
MERose

Ответы:


114

Это не очень эффективно, но сработает, если вам нужны шаблоны глобусов (например, / var / www / *).

for f in $(cat 1.txt) ; do 
  rm "$f"
done

Если у вас нет шаблонов и вы уверены, что ваши пути в файле не содержат пробелов или других странных вещей, вы можете использовать xargs следующим образом:

xargs rm < 1.txt

4
Что произойдет с первым решением (с использованием CAT), если путь содержит пробел?
a.dibacco

58

Предполагая, что список файлов находится в файле 1.txt, выполните:

xargs rm -r <1.txt

Параметр -rвызывает рекурсию в любые каталоги, указанные в 1.txt.

Если какие-либо файлы доступны только для чтения, используйте -fопцию принудительного удаления:

xargs rm -rf <1.txt

Будьте осторожны с вводом в любой инструмент, который выполняет программное удаление. Сделать уверены , что файлы , перечисленные в файле ввода действительно должны быть удалены. Будьте особенно осторожны с кажущимися простыми опечатками. Например, если вы введете пробел между файлом и его суффиксом, это будет выглядеть как два разных имени файла:

file .txt

на самом деле два отдельных файла: fileи .txt.

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

myoldfiles *

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


1
"myoldfiles /" или "/ tmp" еще более опасны с -rf. Обратите внимание на пробел рядом с "/".
Ray

23

Использовать это:

while IFS= read -r file ; do rm -- "$file" ; done < delete.list

Если вам нужно расширение glob, вы можете не цитировать $file:

IFS=""
while read -r file ; do rm -- $file ; done < delete.list

Но имейте в виду, что имена файлов могут содержать «проблемный» контент, и я бы использовал версию без кавычек. Представьте себе этот узор в файле

*
*/*
*/*/*

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


3
Это в настоящее время единственный ответ , который обрабатывает все /My Dir With Spaces/ /Spaces and globs/*.txt, --file-with-leading-dashesи в качестве бонуса это POSIX и работает на GNU / Linux, MacOS и BSD.
тот другой парень

17

Вы можете использовать '\ n' для определения символа новой строки как разделителя.

xargs -d '\n' rm < 1.txt

Будьте осторожны с -rf, потому что он может удалить то, что вы не хотите, если 1.txt содержит пути с пробелами. Вот почему новый разделитель строк немного безопаснее.

В системах BSD вы можете использовать параметр -0, чтобы использовать символы новой строки в качестве разделителя, например:

xargs -0 rm < 1.txt

1
На OS X это меня xargs: illegal option -- d
поймет

Хорошая точка зрения. Кажется, нет другого выхода, кроме -0OS X.
Рэй

2
xargs -I_ rm _также работает в OS X :) см. stackoverflow.com/a/39335402/266309
waldyrious

Если вы используете BSD xargs (где его нет -d), вы можете сначала преобразовать символы новой строки в нули:tr '\n' '\0' < 1.txt | xargs -0 rm
OrangeDog

14

Вы можете использовать этот однострочник:

cat 1.txt | xargs echo rm | sh

Что делает расширение оболочки, но выполняется rmминимальное количество раз.


Если любое расширение не будет слишком длинным?
Дуглас Лидер

1
Правда, глобус может создать слишком длинный список аргументов - вы можете добавить -n <n>аргумент, чтобы xargsуменьшить количество аргументов, передаваемых каждому rm, но это все равно не защитит вас от единственного глобуса, превышающего лимит.
tgdavies

13

xargs -I{} sh -c 'rm {}' < 1.txtдолжен делать то, что хочешь. Будьте осторожны с этой командой, поскольку одна неверная запись в этом файле может вызвать много проблем.

Этот ответ был отредактирован после того, как @tdavies указал, что в оригинале не выполнялось расширение оболочки.


Спасибо, но папки удалять не нужно, только файлы
Александр

2
Шарики не будут расширяться, так как оболочка их никогда не «видит».
tgdavies

@tdavies вау - ты прав. Эта команда (хотя и немного уродливая) будет работать:xargs -I{} sh -c 'rm {}' < 1.txt
Марк Драго

4

В этом конкретном случае из-за опасностей, указанных в других ответах, я бы

  1. Отредактируйте, например, в Vim и :%s/\s/\\\0/g, экранируя все символы пробела обратной косой чертой.

  2. Затем :%s/^/rm -rf /, добавив команду. С -rвами не придется беспокоиться иметь каталоги , перечисленные после того , как файлы , содержащиеся в нем, и с -fним не будет жаловаться из - за недостающие файлы или повторяющиеся записи.

  3. Выполните все команды: $ source 1.txt


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

4

cat 1.txt | xargs rm -f | bash Выполнение команды сделает следующее только для файлов.

cat 1.txt | xargs rm -rf | bash Выполнение команды приведет к следующему рекурсивному поведению.


2

Чтобы предоставить другой способ, вы также можете просто использовать следующую команду

$ cat to_remove
/tmp/file1
/tmp/file2
/tmp/file3
$ rm $( cat to_remove )

1

Вот еще один пример зацикливания. Этот также содержит оператор if в качестве примера проверки, является ли запись «файлом» (или, например, «каталогом»):

for f in $(cat 1.txt); do if [ -f $f ]; then rm $f; fi; done

0

Здесь вы можете использовать набор папок из deletelist.txt в то время как избежать некоторых моделей , а также

foreach f (cat deletelist.txt)
    rm -rf ls | egrep -v "needthisfile|*.cpp|*.h"
end

0

Это позволит именам файлов иметь пробелы (воспроизводимый пример).

# Select files of interest, here, only text files for ex.
find -type f -exec file {} \; > findresult.txt
grep ": ASCII text$" findresult.txt > textfiles.txt
# leave only the path to the file removing suffix and prefix
sed -i -e 's/:.*$//' textfiles.txt
sed -i -e 's/\.\///' textfiles.txt

#write a script that deletes the files in textfiles.txt
IFS_backup=$IFS
IFS=$(echo "\n\b")
for f in $(cat textfiles.txt); 
do 
rm "$f"; 
done
IFS=$IFS_backup

# save script as "some.sh" and run: sh some.sh

0

В случае, если кто-то предпочитает sedудаление без подстановки :

sed -e "s/^\(.*\)$/rm -f -- \'\1\'/" deletelist.txt | /bin/sh

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

И для полноты то же самое с awk:

awk '{printf "rm -f -- '\''%s'\''\n",$1}' deletelist.txt | /bin/sh

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.