untuk loop di folder dengan \ n karakter di namanya

9

Saya memiliki beberapa folder dengan \nkarakter itu nama mereka.

sebagai contoh:

$ ls
''$'\n''Test'

Thats merujuk ke folder dengan nama Tes dan baris kosong sebelum namanya.

Jadi ketika saya menjalankan beberapa skrip seperti ini, di direktori induknya:

while IFS= read -r d; do 
    rmdir $d
done < <(find * -type d)

Itu menunjukkan:

rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory

Karena berjalan dua kali, sekali aktif \ndan yang lain aktif Test, karena nama folder memiliki dua baris.

Jadi bagaimana saya bisa mengatasi masalah ini sehingga, skrip tahu \nTesthanya satu folder?

Tara S Volpe
sumber
3
Anda perlu menggunakan -print0arahan find , dan -dopsi baca. Lihat stackoverflow.com/a/40189667/7552
glenn jackman
1
@glennjackman Harap jawab!
hidangan penutup
@ glennjackman Terima kasih atas balasan Anda tetapi find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; doneperintah memiliki output ini rmdir: failed to remove 'Test': No such file or directory.
Tara S Volpe
5
Anda harus mengutip variabel:rmdir "$file"
glenn jackman
1
@glennjackman Cukup posting ini sebagai jawaban. Ini solusi yang tepat dan selain itu komentar bukanlah tempat terbaik untuk itu. Suara positif sudah tersirat :)
Sergiy Kolodyazhnyy

Jawaban:

12

Anda hanya memiliki satu perintah di sana, jadi cukup untuk menelepon finddengan -execflag flag rmdir:

find -depth -type d -exec rmdir {} \;

Atau gunakan -deleteopsi seperti pada find -type d -delete, tetapi itu tidak akan berfungsi dengan direktori tidak kosong. Untuk itu Anda juga perlu -emptybendera. Perhatikan juga, -deletemenyiratkan -depthagar dapat dilewati. Dengan demikian alternatif lain yang memungkinkan yang menjadikan semuanya sebagai satu proses:

find -type d -empty -delete

Jika direktori tidak kosong, gunakan rm -rf {} \;. Untuk mengisolasi hanya direktori dengan \nnama file, kami dapat menggabungkan kutipan ANSI-C bash $'...'dengan -nameopption:

find  -type d -name $'*\n*' -empty -delete

POSIX-ly, kita bisa mengatasinya dengan cara ini:

find -depth  -type d -name "$(printf '*\n*' )" -exec rmdir {} \;

Perlu disebutkan bahwa jika tujuan Anda adalah penghapusan direktori, maka -deletesudah cukup, namun jika Anda ingin menjalankan perintah pada direktori maka -execyang paling sesuai.

Lihat juga

Sergiy Kolodyazhnyy
sumber
2
... gunakan rm -rf dengan hati-hati . ; P Tidak findpunya -deleteopsi btw? Menghapus direktori kosong dan melempar kesalahan untuk yang tidak kosong seperti rmdir- mungkin lebih murah.
hidangan penutup
3
@Don't melakukannya dan saya menambahkannya, tetapi -deletetidak akan menghapus direktori yang tidak kosong. Oleh karena itu, hati-hati penggunaanrm -rf
Sergiy Kolodyazhnyy
6
Selalu kering-lari seperti findperintah tanpa muatan yang merusak (yaitu menghapus -deleteatau -exec whatever \;) untuk memeriksa apakah daftar file yang terkena sebenarnya benar dan tidak mengandung hal-hal yang seharusnya tidak bisa dihapus ...
Byte Komandan
2
Ini adalah askubuntu.com sehingga kami dapat menganggap GNU find. Gunakan -exec rmdir {} +untuk mengelompokkan beberapa argumen ke dalam satu rmdirbaris perintah. Dan BTW " tetapi itu tidak akan bekerja dengan direktori yang tidak kosong. " Juga berlaku rmdir, jadi itu sebenarnya bukan perbedaan -delete. Ini perbedaan dari rm -r.
Peter Cordes
2
find -type d -empty -delete( -deletetersirat -depth).
Kevin
10

Anda bisa menggunakan shell shell alih-alih find:

for d in */ ; do 
    rmdir "$d"
done

Shell glob */cocok dengan semua folder di direktori saat ini. Konstruksi for-loop ini menangani pemisahan kata yang benar secara otomatis.

Perhatikan bahwa tergantung pada opsi shell Anda, ini mungkin mengabaikan folder tersembunyi (nama dimulai dengan a.). Perilaku itu dapat diubah untuk mencocokkan semua file untuk sesi saat ini menggunakan perintah shopt -s dotglob.

Juga jangan lupa untuk selalu mengutip variabel Anda.

Komandan Byte
sumber
glob hanya akan menemukan file / direktori di direktori saat ini, tidak secara rekursif seperti findhalnya
ilkkachu
1
Anda benar @ilkkachu. Itu bisa diubah dengan mengaktifkan opsi shell globstar shopt -s globstardan menggunakan **/*/glob sebagai gantinya.
Byte Commander
6

Kedua jawaban yang ditulis sejauh ini memanggil rmdirsekali per direktori, tetapi karena rmdirdapat mengambil beberapa argumen saya bertanya-tanya: Apakah tidak ada cara yang lebih efisien?

Seseorang bisa melakukannya

rmdir */

dan itu jelas merupakan cara termudah dan paling efisien, tetapi mungkin menimbulkan kesalahan dalam banyak direktori (lihat Berapa panjang maksimum argumen baris perintah di gnome-terminal? ). Jika Anda ingin pendekatan ini bekerja secara rekursif, aktifkan globstaropsi shell dengan shopt -s globstardan gunakan **/*/sebagai gantinya */.

Dengan GNU find(dan jika kita tidak ingin menggunakannya -delete), kita bisa melakukannya

find -depth -type d -exec rmdir {} +

yang membangun baris perintah “dengan cara yang sama dengan yang xargsmembangun baris perintahnya” ( man find). Pengganti -depthuntuk -maxdepth 1jika Anda tidak ingin bekerja secara rekursif.

Cara ketiga dan IMO yang brilian dijelaskan oleh steeldriver dalam jawaban ini :

printf '%s\0' */ | xargs -0 rmdir

Ini menggunakan shell builtin printfuntuk membangun daftar argumen nol-dibatasi, daftar ini kemudian disalurkan ke xargspanggilan yang rmdirtepat sesering yang diperlukan. Anda dapat membuatnya bekerja secara rekursif dengan shopt -s globstardan **/*/bukannya */seperti di atas.

pencuci mulut
sumber
2
findbersifat rekursif, tetapi loop OP tidak. Untuk meniru perilaku itu, gunakan find -maxdepth 1 -type d -exec rmdir {} +. ( -depthberlebihan dalam hal itu.) Trik rapi printfuntuk ditiru find -print0, saya belum pernah melihat itu sebelumnya.
Peter Cordes
1
Oh! Saya melihat lsdan whileloop, saya melewatkan bahwa mereka mengarahkan dari proses substitusi dengan findbukannya menyalurkan lske dalam loop dan hanya tidak menunjukkannya untuk beberapa alasan. Itu find *benar-benar terkubur. Ya itu bersifat rekursif, dan akan gagal jika ada terlalu banyak entri direktori dalam direktori, termasuk non-direktori karena tidak digunakan */. find .akan jauh lebih baik, karena findlebih cepat statdaripada ekspansi global bash.
Peter Cordes