Bagaimana cara menghapus direktori berdasarkan output `find`?

148

Saya mengeluarkan perintah berikut untuk menemukan direktori .svn:

find . -name ".svn"

Itu memberi saya hasil berikut:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn

Bagaimana saya bisa memproses semua baris ini dengan rm -frtujuan untuk menghapus direktori dan isinya?

Arnaud
sumber
3
GNU find memiliki -deleteopsi.
Marco
5
Atau Anda dapat menambahkan -exec rm -r "{}" \;di akhir pencarian - berhati-hatilah saat menggunakan rm -r! :)
Drav Sloan
10
@Marco Opsi hapus sepertinya tidak berfungsi di direktori.
Arnaud
@SuperChafouin Ini bekerja dengan sangat baik di sini di file dan direktori. Intinya adalah bahwa itu hanya menghapus direktori emtpy dan ketika Anda menentukannya -name ".svn"hanya cocok dengan .svndirektori itu sendiri dan bukan file yang terletak di .svndirektori.
Marco
1
@ SupupChafouin tetapi tidak akan bekerja untuk jalur dengan spasi di dalamnya (karenanya menggunakan -execdengan dikutip "{}").
Drav Sloan

Jawaban:

195

Find dapat mengeksekusi argumen dengan -execopsi untuk setiap kecocokan yang ditemukannya. Ini adalah mekanisme yang disarankan karena Anda dapat menangani jalur dengan spasi / baris baru dan karakter lain di dalamnya dengan benar. Anda harus menghapus isi direktori sebelum Anda dapat menghapus direktori itu sendiri, jadi gunakan -rdengan rmperintah untuk mencapai ini.

Sebagai contoh, Anda dapat menerbitkan:

find . -name ".svn" -exec rm -r "{}" \;

Anda juga dapat memberi tahu find untuk hanya menemukan direktori bernama .svn dengan menambahkan tanda -type dcentang:

find . -name ".svn" -type d -exec rm -r "{}" \;

Peringatan Gunakan rm -rdengan hati-hati menghapus folder dan semua isinya.

Jika Anda ingin menghapus hanya direktori kosong dan juga direktori yang hanya berisi direktori kosong, temukan dapat melakukannya sendiri dengan -deletedan -empty:

find . -name ".svn" -type d -empty -delete
Drav Sloan
sumber
22
Saya telah melihat saran untuk selalu menjalankan -type setelah -name dalam menemukan perintah, karena panggilan statuntuk mendapatkan jenis itu mahal. Saya baru saja mencobanya sendiri di banyak file, dan tampaknya benar: menjalankan find . -name 'foo' -type dmengambil 19 detik, sementara find . -type d -name 'foo'mengambil 32 detik. Jadi sekitar 50% lebih lama waktu untuk berjalan -typeterlebih dahulu.
spinup
6
Saya telah menggunakan perintah ini selama bertahun-tahun, tetapi pada Mac sekarang saya mendapatkan kesalahan dengan mengatakan direktori tersebut tidak ada. Meskipun itu menghapusnya. Saya tidak pernah melihat pesan sebelumnya.
chovy
1
Sama seperti @chovy. Apakah ada cara untuk menghilangkan pesan-pesan ini?
Clément
2
@chovy @ clément Itu karena findingin melihat di folder itu untuk pertandingan lain, sementara itu menghapus folder pada saat bersamaan. ~ Aku belum tahu bagaimana memperbaikinya. ~ Memperbaiki kotor:find . -name "folder-to-delete" -print0 | xargs -r0 -- rm -r
Charlie
5
@ chovy @ Clément Saya pikir -depthargumennya akan memperbaiki ini:find . -depth -name ".svn" -type d -exec rm -r "{}" \;
gimboland
67

Ini adalah portable yang masih lebih cepat daripada cara menjawab yang diterima.

Menggunakan +bukannya titik koma sebagai findterminator perintah mengoptimalkan penggunaan CPU. Itu bisa menjadi signifikan jika Anda memiliki banyak .svnsubdirektori:

find . -name .svn -type d -exec rm -rf {} +

Perhatikan juga bahwa Anda tidak pernah 1 perlu mengutip kurung kurawal di sini.

1 Kecuali Anda menggunakan fishshell.

Jlliagre
sumber
5
Apa perbedaan antara + dan titik koma? Kenapa kita tidak menggunakan kurung kurawal?
Shicheng Guo
1
@ShichengGuo Dengan titik koma, akan ada satu perintah rm per direktori ditemukan, dengan perintah + a rm tunggal akan memproses semua direktori yang ditemukan (atau setidaknya sejumlah besar dari mereka.) Saya tidak mendapatkan pertanyaan kedua, keriting kawat gigi digunakan di sini.
jlliagre
Saya pikir @ShichengGuo berarti mengapa kita tidak perlu mengutip kurung kurawal di sini (@ jlliagre menulis bahwa kita tidak perlu mengutipnya). Saya tidak dapat menemukan referensi sekarang, tetapi saya memahaminya karena find akan secara otomatis keluar dari jalur yang diganti untuk {}.
Quinn Comendant
Jawaban dan pertanyaannya kurang tepat tentang apa yang dilakukan +. Jika banyak file ditemukan maka ';' akan memberikan kesalahan 'command line too long'. + Memecah file yang ditemukan dalam batch yang kurang dari max panjang baris perintah yang diizinkan dan menjalankan perintah untuk setiap batch.
gaoithe
1
@gaoithe saya melakukan rollback yang Anda edit yang menggantikan pernyataan yang benar dengan yang salah. Menggunakan + tidak mengurangi penggunaan CPU, Menggunakan ; tidak menyebabkan kesalahan perintah terlalu lama.
jlliagre
27

Asumsikan Anda menggunakan gnu find , Anda dapat menggunakan -deleteopsi:

find . -name test -delete

yang lebih mudah diingat.

Chun Yang
sumber
Pertimbangkan memperluas posting Anda dengan penjelasan perintah (atau dokumentasi untuk mendukung solusi Anda). Seringkali satu (atau dua) jawaban baris bukan yang paling menerangi.
HalosGhost
94
Ini tidak berfungsi pada direktori yang tidak kosong.
belacqua
2
juga bekerja di Mac OS X
draw
Ini tidak berfungsi untuk folder yang tidak kosong tetapi ini adalah solusi yang lebih mudah & aman
RousseauAlexandre
Urutan opsi sangat penting, temukan akan mengeksekusinya agar, -hapus harus menjadi yang terakhir
Jose Ignacio Centeno
13

Di komputer saya ketika saya menggunakan:

find . \( -name dirname -type d \) -exec rm -r '{}' ';'

Direktori dihapus tetapi saya mendapatkan kesalahan:

find: ‘./dirname’: No such file or directory

untuk setiap direktori.

Direktori saya tidak kosong, jadi opsi -delete tidak akan berfungsi untuk saya. Saya menemukan alasan perilaku ini di sini :

  1. find mengambil (belum tentu) entri pertama dalam direktori ./. ini akan menjadi misalnya dir.1 /
  2. itu membandingkannya dengan pola 'dir.?'. apakah ini cocok? Iya.
  3. temukan eksekusi "rm -r dir.1".
  4. find mencoba memasukkan dir.1 / untuk menemukan pola di dalam direktori. tidak tahu apa-apa tentang perintah exec.
  5. tidak menemukan dir.1 / lagi. mengembalikan ENOENT (lihat output strace)

Saya menggunakan ini sebagai gantinya:

rm -r `find . -name dirname -type d`

Ingatlah bahwa find masih akan mencoba untuk kembali ke direktori bernama dirname, yang sebenarnya tidak perlu dan akan membutuhkan waktu tambahan. Bergantung pada struktur direktori Anda, Anda mungkin dapat mengatasinya dengan --depthopsi find. Selain itu, jika Anda memiliki struktur direktori seperti dirname / foo / dirname Anda akan mendapatkan kesalahan "Tidak ada file atau direktori" dari rm. Untuk menekan kesalahan, Anda dapat mengarahkan stderr ke / dev / null atau menggunakan -fflag (force) dengan rm.

Samuel
sumber
2
Gagasan buruk: nama file dengan spasi akan menyebabkan segala macam masalah mengerikan
Clément
2
Untuk pembaca di masa depan: find . -name "to-delete" -print0 | xargs -r0 -- rm -radalah versi anti gagal yang tidak menabrak ruang
Charlie
3
Lihat unix.stackexchange.com/a/115869/8257 yang perlu Anda tambahkan -prune.
Mapio
1
Tambahkan -pruneuntuk menghindari kesalahan "Tidak ada file atau direktori".
Julien Carsique
12

Cara yang lebih cepat untuk melakukan ini adalah:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'

Jika Anda memiliki ".svn" di dalam yang lain ".svn".

Chang Yu-heng
sumber
Itu tidak terlalu berguna jika Anda ingin menemukan direktori untuk dihapus dengan sub-direktori.
Alexis Wilke
5

Solusi spesifik Bash:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion
buru-buru
sumber
3
Catatan untuk ekspansi baris perintah dari gumpalan yang cocok dengan banyak file, ada batas jumlah file yang dapat Anda cocokkan dengan mekanisme ini. Melampaui batas ini akan menghasilkanbash: /bin/rm: Argument list too long
Drav Sloan
1
@ DravSloan benar, tetapi batas itu ada di ratusan ribu file. Ini adalah sesuatu yang perlu diingat, tetapi mungkin tidak akan menjadi masalah bagi kebanyakan orang.
evilsoup
4

Saya telah menemukan bahwa -deletetindakannya bekerja dengan baik dengan -pathtes. Sebagai contoh, berikut ini harus bekerja pada masalah poster asli:

find . -path '*/.svn*' -delete
Magnus
sumber
Apakah kamu yakin -deletetersirat -depth, dan itu pasti menghapus direktori tidak kosong di sistem saya.
Magnus
Diuji ulang dan berhasil. Mungkin itu hanya kesalahan ketik yang saya koreksi.
kenorb
Saya juga mencoba pendekatan ini dan berhasil - direktori dihapus.
Allan