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

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

*
*/*
*/*/*

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

hek2mgl
источник
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минимальное количество раз.

tgdavies
источник
Если любое расширение не будет слишком длинным?
Дуглас Лидер
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
n-й параметр
источник
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

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

Марко
источник