Unix: Cara menghapus file yang terdaftar dalam sebuah file

92

Saya memiliki file teks panjang dengan daftar file mask yang ingin saya hapus

Contoh:

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

Saya perlu menghapusnya. Mencoba rm `cat 1.txt` dan dikatakan daftar itu terlalu panjang.

Menemukan perintah ini, tetapi ketika saya memeriksa folder dari daftar, beberapa dari mereka masih memiliki file. xargs rm <1.txtPanggilan rm manual menghapus file dari folder tersebut, jadi tidak ada masalah dengan izin.

Alexander
sumber
8
Meskipun enam tahun kemudian: Maukah Anda menerima salah satu jawaban? Ini akan menandai pertanyaan sebagai terselesaikan dan membantu pengguna lain juga.
MERose

Jawaban:

115

Ini tidak terlalu efisien, tetapi akan berfungsi jika Anda membutuhkan pola glob (seperti di / var / www / *)

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

Jika Anda tidak memiliki pola apa pun dan yakin jalur Anda dalam file tersebut tidak berisi spasi putih atau hal-hal aneh lainnya, Anda dapat menggunakan xargs seperti ini:

xargs rm < 1.txt
no
sumber
4
Apa yang akan terjadi dengan solusi pertama (menggunakan CAT) jika jalur berisi spasi?
Tembakau
58

Dengan asumsi bahwa daftar file ada di dalam file 1.txt, lakukan:

xargs rm -r <1.txt

The -rpilihan menyebabkan rekursi ke setiap direktori yang disebutkan dalam 1.txt.

Jika ada file yang bersifat baca-saja, gunakan -fopsi untuk memaksa penghapusan:

xargs rm -rf <1.txt

Berhati-hatilah dengan masukan ke alat apa pun yang melakukan penghapusan terprogram. Membuat tertentu bahwa file di dalam file masukan yang benar-benar akan dihapus. Berhati-hatilah dengan kesalahan ketik yang tampaknya sederhana. Misalnya, jika Anda memasukkan spasi antara file dan sufiksnya, itu akan tampak menjadi dua nama file yang terpisah:

file .txt

sebenarnya adalah dua file terpisah: filedan .txt.

Ini mungkin tidak terlalu berbahaya, tetapi jika kesalahan ketiknya seperti ini:

myoldfiles *

Kemudian alih-alih menghapus semua file yang dimulai dengan myoldfiles, Anda akan berakhir dengan menghapus myoldfilesdan semua file non-dot dan direktori di direktori saat ini. Mungkin bukan yang Anda inginkan.

aks
sumber
1
"myoldfiles /" atau "/ tmp" bahkan lebih berbahaya dengan -rf. Perhatikan karakter spasi di samping "/".
Ray
24

Gunakan ini:

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

Jika Anda membutuhkan ekspansi global, Anda dapat menghilangkan kutipan $file:

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

Tetapi berhati-hatilah bahwa nama file dapat berisi konten yang "bermasalah" dan saya akan menggunakan versi yang tidak dikutip. Bayangkan pola ini di file

*
*/*
*/*/*

Ini akan menghapus cukup banyak dari direktori saat ini! Saya akan mendorong Anda untuk menyiapkan daftar hapus dengan cara yang pola glob tidak diperlukan lagi, dan kemudian gunakan kutipan seperti pada contoh pertama saya.

hek2mgl
sumber
3
Ini adalah saat-satunya jawaban yang menangani semua /My Dir With Spaces/ /Spaces and globs/*.txt, --file-with-leading-dashesdan sebagai bonus itu POSIX dan bekerja pada GNU / Linux, MacOS dan BSD.
orang lain itu
17

Anda bisa menggunakan '\ n' untuk mendefinisikan karakter baris baru sebagai pembatas.

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

Hati-hati dengan -rf karena dapat menghapus apa yang tidak Anda inginkan jika 1.txt berisi path dengan spasi. Itu sebabnya pembatas baris baru sedikit lebih aman.

Pada sistem BSD, Anda dapat menggunakan opsi -0 untuk menggunakan karakter baris baru sebagai pembatas seperti ini:

xargs -0 rm < 1.txt
sinar
sumber
1
Di OS X, hal ini membuat sayaxargs: illegal option -- d
waldyrious pada tanggal
Poin yang bagus. Sepertinya tidak ada pilihan lain selain -0di OS X.
Ray
2
xargs -I_ rm _juga bekerja di OS X :) lihat stackoverflow.com/a/39335402/266309
waldyrious
Jika menggunakan xarg BSD (di mana tidak ada -d), Anda dapat mengubah baris baru menjadi nulls terlebih dahulu:tr '\n' '\0' < 1.txt | xargs -0 rm
OrangeDog
15

Anda dapat menggunakan satu baris ini:

cat 1.txt | xargs echo rm | sh

Yang melakukan ekspansi shell tetapi mengeksekusi rmjumlah minimum kali.

tgdavies.dll
sumber
Selama ekspansi tidak terlalu lama?
Douglas Leeder
1
Benar, sebuah glob bisa menghasilkan daftar argumen yang terlalu panjang - Anda bisa menambahkan -n <n>argumen ke xargsuntuk mengurangi jumlah argumen yang diteruskan ke setiap rm, tetapi itu tetap tidak akan melindungi Anda dari satu glob yang melebihi batas.
tgdavies
13

xargs -I{} sh -c 'rm {}' < 1.txtharus melakukan apa yang kamu inginkan. Berhati-hatilah dengan perintah ini karena satu entri yang salah dalam file itu dapat menyebabkan banyak masalah.

Jawaban ini diedit setelah @tdavies menunjukkan bahwa aslinya tidak melakukan ekspansi shell.

Tandai Drago
sumber
Terima kasih, tetapi tidak perlu menghapus folder, hanya file
Alexander
2
Gumpalan tidak akan mengembang, karena tidak pernah 'dilihat' oleh cangkangnya.
tgdavies
@tdavies wow - kamu benar. Perintah ini (meskipun sedikit lebih jelek) akan berfungsi:xargs -I{} sh -c 'rm {}' < 1.txt
Mark Drago
4

Dalam kasus khusus ini, karena bahaya yang dikutip dalam jawaban lain, saya akan melakukannya

  1. Edit di misalnya Vim dan :%s/\s/\\\0/g, keluar dari semua karakter spasi dengan garis miring terbalik.

  2. Lalu :%s/^/rm -rf /, prapenjualan perintah. Dengan -rAnda tidak perlu khawatir memiliki direktori yang terdaftar setelah file yang ada di dalamnya, dan dengan -fitu tidak akan mengeluh karena file yang hilang atau entri duplikat.

  3. Jalankan semua perintah: $ source 1.txt

Evgeni Sergeev
sumber
Spasi bukan satu-satunya karakter yang perlu keluar, populer di nama file juga tanda kurung dalam bentuk apa pun yang dapat menyebabkan ekspansi yang tidak diinginkan.
emk2203
4

cat 1.txt | xargs rm -f | bash Jalankan perintah ini akan melakukan hal berikut hanya untuk file.

cat 1.txt | xargs rm -rf | bash Jalankan perintah akan melakukan perilaku rekursif berikut.

Uzayr
sumber
2

Sekadar memberikan cara lain, Anda juga bisa langsung menggunakan perintah berikut

$ cat to_remove
/tmp/file1
/tmp/file2
/tmp/file3
$ rm $( cat to_remove )
Quentin
sumber
1

Berikut contoh perulangan lainnya. Yang ini juga berisi 'if-statement' sebagai contoh pemeriksaan untuk melihat apakah entri adalah 'file' (atau 'directory' misalnya):

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

Di sini Anda dapat menggunakan sekumpulan folder dari deletelist.txt sambil menghindari beberapa pola juga

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

Ini akan memungkinkan nama file memiliki spasi (contoh yang dapat direproduksi).

# 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
Ferroao
sumber
0

Jika seseorang lebih suka seddan menghapus tanpa perluasan karakter pengganti :

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

Pengingat: gunakan nama path absolut dalam file atau pastikan Anda berada di direktori yang benar.

Dan untuk kelengkapannya sama dengan awk:

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

Perluasan karakter pengganti akan berfungsi jika tanda kutip tunggal dihapus, tetapi ini berbahaya jika nama file berisi spasi. Ini perlu menambahkan tanda kutip di sekitar wildcard.

Marco
sumber