Saya ingin secara rekursif menghapus semua file yang tidak diakses dalam folder sementara a
, kecuali semua file dalam subfolder b
.
find a \( -name b -prune \) -o -type f -delete
Namun, saya mendapatkan pesan kesalahan:
find: Tindakan -delete secara otomatis mengaktifkan -depth, tetapi -prune tidak melakukan apa-apa ketika -depth berlaku. Jika Anda tetap ingin melanjutkan, cukup gunakan opsi -depth secara eksplisit.
Menambahkan -depth
menyebabkan semua file b
dimasukkan, yang tidak boleh terjadi.
Adakah yang tahu cara aman untuk membuat ini bekerja?
a
kecualia/b
?cd a && ls -d !(b/*)
bekerja (Untuk melakukannya, hanyarm -r
daripadals -d
.)a
(kecuali file di bawaha/b
).-r
ke rm. Sepertinya apa yang Anda tanyakan cukup mudah dijawab dengan menggunakan bash's globbing yang diperluas, dan kemudian apa yang Anda lakukan dengan hasil globbing itu terserah Anda.Jawaban:
TL; DR: cara terbaik adalah menggunakan
-exec rm
alih-alih-delete
.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
:Tidak ada jaminan tentang pesanan dalam satu direktori. Tetapi ada jaminan bahwa direktori diproses sebelum isinya. Catat
foo/
sebelumfoo/*
danfoo/bar
sebelum apa punfoo/bar/*
.Ini dapat dibalik dengan
-depth
.Perhatikan bahwa sekarang semua
foo/*
muncul sebelumnyafoo/
. Sama denganfoo/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 namab
.-depth
make find untuk memproses isi direktori sebelum direktori itu sendiri. Itu berarti pada saat ditemukan dapat memproses entri direktorib
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:
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 direktorib
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 namanyabar
.-path "*/foo*"
akan cocok karena string/foo
ada di jalur.-path
memiliki beberapa seluk yang harus Anda pahami sebelum menggunakannya. Baca halaman manualfind
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 denganb
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
danb
sebagai placeholder dan nama asli lebih miripallosaurus
danbrachiosaurus
. Jika Anda meletakkanbrachiosaurus
di tempatb
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.sumber
-not -path
itu masalahnya! Terima kasih untuk penjelasannya!-not -path
bekerja sementara-prune
tidak akan membantu. Mengapa bisa-not -path
hidup berdampingan dengan-depth
?Gunakan saja
rm
alih-alih-delete
:sumber
rm
berhasil dandelete
tidak?rm
tidak memiliki masalah itu. Namun, bagaimanapun juga, elaborasi akan menjadi hal yang baik.-delete
tersirat-depth
, yang jelas tidak bisa bekerja dengan-prune
.-path
berfungsi, tetapi tidak berhentifind
turun di direktori yang tidak perlu dijelajahi.Jawaban dan penjelasan di atas sangat membantu.
Saya menggunakan solusi "-exec rm {} +" atau "-not -path ... -delete ', tetapi itu bisa lebih lambat dari" find ... -delete ". Saya telah melihat" find ... -hapus "jalankan 5x lebih cepat dari" -exec rm {} + "pada direktori yang dalam pada sistem file NFS.
Solusi '-not path "memiliki overhead yang jelas untuk melihat semua file di direktori yang dikecualikan dan di bawah.
"Find .. -exec rm {} +" memanggil rm yang melakukan panggilan sistem:
"Find -delete" melakukan panggilan sistem:
Jadi "-exec rm {} +" perintah rm melakukan path lengkap ke inode lookup dua kali dua kali per file, tetapi "find -delete" melakukan stat dan putuskan tautan nama file di direktori saat ini. Itu adalah kemenangan besar ketika Anda menghapus banyak file dalam satu direktori.
(mode merengek aktif (maaf))
Sepertinya desain interaksi antara -depth, -delete dan -prune tidak perlu menghilangkan cara paling efisien untuk melakukan tindakan umum "menghapus file kecuali yang ada di direktori -prune"
Kombinasi "-type f -delete" harus dapat dijalankan tanpa -depth karena tidak mencoba untuk menghapus direktori. Atau, jika "find" memiliki tindakan "-deletefile" yang mengatakan jangan hapus direktori, -depth tidak perlu diimplikasikan.
Perintah xargs atau find -exec to rm dapat dipercepat jika rm memiliki opsi untuk mengurutkan nama file, membuka direktori, dan melakukan unlinkat (dir_fd, nama file) alih-alih memutus tautan jalur lengkap. Itu sudah melakukan unlinkat (dir_fd, nama file) ketika berulang melalui direktori dengan opsi -r.
(mode merengek mati)
sumber