Unix: Як видалити файли, перелічені у файлі


93

У мене довгий текстовий файл зі списком масок файлів, які я хочу видалити

Приклад:

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

Мені потрібно їх видалити. Спробував rm `cat 1.txt`, і там сказано, що список задовгий.

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


8
Незважаючи на те, що це пройшло шість років потому: Ви б не прийняли одну з відповідей? Це позначить питання як вирішене і допоможе іншим користувачам.
МЕРО,

Відповіді:


117

Це не дуже ефективно, але буде працювати, якщо вам потрібні шаблони глобусів (як у / var / www / *)

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

Якщо у вас немає шаблонів і ви впевнені, що ваші шляхи у файлі не містять пробілів чи інших дивних речей, ви можете використовувати xargs приблизно так:

xargs rm < 1.txt

4
Що станеться з першим рішенням (за допомогою CAT), якщо шлях містить пробіл?
a.dibacco

59

Припустивши, що список файлів є у файлі 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. Зверніть увагу на пробіл біля символу "/".
Рей

24

Використовуй це:

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

Якщо вам потрібно розширити глобус, ви можете пропустити цитування $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

15

Ви можете використовувати цей однокласник:

cat 1.txt | xargs echo rm | sh

Що робить розширення оболонки, але виконує rmмінімальну кількість разів.


Поки будь-яке розширення не надто довге?
Douglas Leeder

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-statement" як приклад перевірки, чи є запис "файлом" (або, наприклад, "каталогом"):

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.