Di Linux, bagaimana saya bisa menemukan semua file yang berisi string dan menghapusnya?

17

Saya ingin menghapus semua file yang berisi string foo. Bagaimana saya bisa melakukan ini menggunakan bash di Linux?

Kitsos
sumber
string itu adalah nama file-nya?
rɑːdʒɑ
3
Tolong jelaskan: apakah Anda ingin menghapus file yang namanya berisi foo(misalnya myfoo.jpg), atau file yang berisi urutan byte foo(yang mungkin termasuk file biner yang kebetulan mengandung urutan byte itu)?
hammar

Jawaban:

33

Ini cara yang aman:

grep -lrIZ foo . | xargs -0 rm -f --
  • -l mencetak nama file dari file yang cocok dengan pola pencarian.
  • -rmelakukan pencarian rekursif untuk pola foodi direktori yang diberikan .. Jika ini tidak berhasil, coba -R.
  • -I(modal i) menyebabkan file biner seperti PDF dilewati.
  • -Z memastikan bahwa nama file nol- (yaitu, nul-) diakhiri sehingga nama yang mengandung spasi tidak ditafsirkan dengan cara yang salah (yaitu, sebagai beberapa nama, bukan satu).
  • xargs -0mengumpankan nama file dari grepmenjadi rm -f, memisahkan kata dengan nol (nul) byte (ingat -Zopsi dari grep).
  • --sering dilupakan tetapi sangat penting untuk menandai akhir opsi dan memungkinkan penghapusan file yang namanya dimulai -.

Jika Anda ingin melihat file mana yang akan dihapus, cukup hapus | xargs -0 rm -f --bagian itu, dan tinggalkan Zopsi untuk grep.

Pengguna lain menyarankan sesuatu seperti yang berikut, yang tidak boleh Anda jalankan karena tidak aman:

files=`grep foo * | cut -d: -f1`
rm -f $files         # unsafe, do not run it!

Jika saya memiliki file ImportantStuffyang saya tidak ingin hapus dan obsolete ImportantStuffmengandung foo, maka saya kehilangan ImportantStuff(dan tidak obsolete ImportantStuff !) Ketika saya menjalankan perintah ini, karena $filesrusak di ruang ketika ditafsirkan. Berbahaya memasukkan daftar nama file ke dalam variabel skalar shell dengan cara ini.

Lekensteyn
sumber
17
$ find -type f -exec grep -q "foo" {} \; -exec echo rm -- {} \;

Ini secara rekursif mencari file yang mengandung foo. Yang kedua -exechanya berjalan jika yang pertama execberhasil, yaitu jika grepcocok. Dryrun dan hapus echojika output tampaknya benar.

Atau sebagai alternatif

$ find -type f -exec grep -q "foo" {} \; -print

dan

$ find -type f -exec grep -q "foo" {} \; -delete

seperti yang disarankan oleh Lekensteyn.

Adrian Frühwirth
sumber
4
... yang dapat disingkat menjadi: find -type f -exec grep -q 'foo' {} \; -delete(tanda kutip di sekitarnya {}berlebihan, findjuga dapat menghapus file.). Perhatikan bahwa grepmenerima ekspresi reguler. Jika Anda ingin mencari foo.bar, lepas ini atau lewat -Fopsi untuk memperlakukan pola sebagai literal.
Lekensteyn
ada alasan untuk menggunakan -exec echo rm "{}" \;dan tidak -delete?
vartec
1
@ vartec Tidak, saya akan menggunakan -delete. Lebih mudah untuk menunjukkan dengan yang kedua -execdan menggema di tempat.
Adrian Frühwirth
1
Lebih mudah untuk mengetik -print(atau -lsuntuk lebih banyak kata) daripada -exec echo rm "{}" \'. Tidak perlu utilitas eksternal.
Lekensteyn
1
jika Anda menggunakan rm {}, gunakan rm - {}, sehingga setiap karakter khusus dalam nama file itu sendiri tidak diinterpolasi. Misalnya, sentuh '-rf /' di direktori mana pun di mana Anda memiliki izin menulis ...
atk
1

Saya akan melakukan apa yang dikatakan Adrian,

Tapi saya akan menambahkan batas kata di foo foo agar tidak sengaja menghapus file yang berisi "makanan" (kecuali itu menghapus semua yang mengandung makanan adalah apa yang Anda inginkan.)

 $ find -type f -exec grep -q "\<foo\>" {} \; -delete

secara akut, saya akan mengarahkan output sebelum menghapus sehingga saya bisa meninjau sebelum menghapus:

 $ find -type f -exec grep -q "\<foo\>" > /tmp/list_of_files_to_delete
Petter H
sumber
Segera setelah Anda dapat memposting komentar, Anda harus memposting hal-hal seperti itu sebagai komentar.
FSMaxB
ya saya mencoba dulu tetapi kemudian menyadari bahwa saya belum diperbolehkan memposting komentar.
Petter H