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.


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

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.


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.


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

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.


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.


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


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.


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 )

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

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

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

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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.