TL; DR: cara terbaik adalah menggunakan -exec rm
alih-alih -delete
.
find a \( -name b -prune \) -o -type f -exec rm {} +
Penjelasan:
Mengapa menemukan mengeluh ketika Anda mencoba untuk menggunakan -delete
dengan -prune
?
Jawaban singkat: karena -delete
menyiratkan -depth
dan -depth
membuat -prune
tidak efektif.
Sebelum kita sampai pada jawaban panjang, pertama-tama amati perilaku menemukan dengan dan tanpa -depth
:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
Tidak ada jaminan tentang pesanan dalam satu direktori. Tetapi ada jaminan bahwa direktori diproses sebelum isinya. Catat foo/
sebelum foo/*
dan foo/bar
sebelum apa pun foo/bar/*
.
Ini dapat dibalik dengan -depth
.
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
Perhatikan bahwa sekarang semua foo/*
muncul sebelumnya foo/
. Sama dengan foo/bar
.
Jawaban yang lebih panjang:
-prune
mencegah menemukan turun ke direktori. Dengan kata lain -prune
melompati isi direktori. Dalam kasus Anda, -name b -prune
mencegah menemukan turun ke direktori apa pun dengan nama b
.
-depth
make find untuk memproses isi direktori sebelum direktori itu sendiri. Itu berarti pada saat ditemukan dapat memproses entri direktori b
isinya telah diproses. Dengan demikian -prune
tidak efektif dengan -depth
efeknya.
-delete
tersirat -depth
sehingga dapat menghapus file pertama dan kemudian direktori kosong. -delete
menolak untuk menghapus direktori yang tidak kosong. Saya kira itu akan mungkin untuk menambahkan pilihan untuk kekuatan -delete
untuk menghapus direktori yang tidak kosong dan / atau untuk mencegah -delete
menyiratkan -depth
. Tapi itu cerita lain.
Ada cara lain untuk mencapai apa yang Anda inginkan:
find a -not -path "*/b*" -type f -delete
Ini mungkin atau mungkin tidak mudah diingat.
Perintah ini masih turun ke direktori b
dan memproses setiap file di dalamnya hanya untuk -not
menolaknya. Ini bisa menjadi masalah kinerja jika direktori b
sangat besar.
-path
bekerja berbeda dari -name
. -name
hanya cocok dengan nama (file atau direktori) saat -path
cocok dengan seluruh jalur. Misalnya mengamati jalannya /home/lesmana/foo/bar
. -name -bar
akan cocok karena namanya bar
. -path "*/foo*"
akan cocok karena string /foo
ada di jalur. -path
memiliki beberapa seluk yang harus Anda pahami sebelum menggunakannya. Baca halaman manual find
untuk lebih jelasnya.
Berhati-hatilah karena ini bukan 100% sangat mudah. Ada kemungkinan "false positive". Cara perintah ditulis di atas akan melewati file apa pun yang memiliki direktori induk yang namanya dimulai dengan b
(positif). Tapi itu juga akan melewatkan file apa pun yang namanya dimulai dengan b
terlepas dari posisi di pohon (false positive). Ini dapat diperbaiki dengan menulis ekspresi yang lebih baik daripada "*/b*"
. Itu dibiarkan sebagai latihan untuk pembaca.
Saya berasumsi bahwa Anda menggunakan a
dan b
sebagai placeholder dan nama asli lebih mirip allosaurus
dan brachiosaurus
. Jika Anda meletakkan brachiosaurus
di tempat b
maka jumlah positif palsu akan berkurang drastis.
Setidaknya positif palsu tidak akan dihapus, sehingga tidak akan tragis. Selanjutnya, Anda dapat memeriksa positif palsu dengan terlebih dahulu menjalankan perintah tanpa -delete
(tapi ingat untuk menempatkan yang tersirat -depth
) dan memeriksa hasilnya.
find a -not -path "*/b*" -type f -depth
a
kecualia/b
?