Kemungkinan besar karena menghapus direktori kerja saat ini tidak akan menjadi ide yang baik.
Alexej Magura
Setuju - Saya suka perilaku default, tetapi tidak konsisten dengan, misalnya find . -print,.
mbroshi
@AlexejMagura walaupun saya bersimpati, saya tidak melihat mengapa menghapus direktori saat ini harus berbeda dari menghapus file yang terbuka. Objek akan tetap hidup sampai referensi ada, dan kemudian sampah dikumpulkan sesudahnya. Anda dapat melakukannya cd ..; rm -r dirdengan shell lain dengan semantik yang cukup jelas ...
Rmano
@Rmano ini benar: itu hanya sesuatu yang tidak akan saya lakukan pada prinsipnya: naik saja direktori lalu hapus direktori saat ini. Saya tidak sepenuhnya yakin mengapa ini menjadi masalah besar - meskipun saya memiliki beberapa kemalangan dengan direktori saat ini tidak ada lagi, seperti jalur relatif tidak lagi berfungsi, tetapi Anda selalu dapat keluar dengan menggunakan jalur absolut - tetapi sebagian dari diri saya hanya mengatakan bahwa itu bukan ide yang baik secara umum.
Alexej Magura
Jawaban:
29
Para anggota findutils menyadarinya , ini kompatibel dengan * BSD:
Salah satu alasan mengapa kami melewatkan penghapusan "." untuk kompatibilitas dengan * BSD, tempat tindakan ini berasal.
The NEWS dalam kode findutils sumber menunjukkan bahwa mereka memutuskan untuk menjaga perilaku:
#20802: If -delete fails, find's exit status will now be non-zero. However, find still skips trying to delete ".".
[MEMPERBARUI]
Karena pertanyaan ini menjadi salah satu topik hangat, jadi saya menyelami kode sumber FreeBSD dan keluar alasan yang lebih meyakinkan.
Setiap direktori selalu berisi entri untuk dirinya sendiri, yang disebut ".", Dan induknya, ".."; ini harus dilewati, atau program akan berulang selamanya .
"loop forever" , ini sama seperti renamemenggambarkannya sebagai "jalur sistem file siklis" di atas.
Saya sedikit memodifikasi kode dan membuatnya berjalan di Kali Linux berdasarkan jawaban ini :
Karena findperintah Anda kembali .sebagai hasilnya. Dari halaman info rm:
Upaya apa pun untuk menghapus file yang komponen nama file terakhirnya adalah '.' atau '..' ditolak tanpa diminta, seperti yang diamanatkan oleh POSIX.
Jadi, sepertinya findhanya menempel pada aturan POSIX dalam kasus ini.
Seharusnya: POSIX adalah raja, ditambah menghapus direktori saat ini dapat menyebabkan beberapa masalah yang sangat besar tergantung pada aplikasi induk dan apa yang tidak. Seperti bagaimana jika direktori saat ini berada /var/logdan Anda menjalankannya sebagai root, berpikir bahwa itu akan menghapus semua subdir dan juga menghapus direktori saat ini?
Alexej Magura
1
Itu teori yang bagus, tetapi manhalaman untuk findmengatakan: "Jika penghapusan gagal, pesan kesalahan dikeluarkan." Mengapa tidak ada kesalahan yang dicetak?
mbroshi
1
@AlexejMagura Menghapus direktori saat ini bekerja dengan baik pada umumnya: mkdir foo && cd foo && rmdir $(pwd). Menghapus .(atau ..) itu tidak berhasil.
Arti menghapus pathname / dot tidak jelas, karena nama file (direktori) di direktori induk yang akan dihapus tidak jelas, terutama di hadapan beberapa tautan ke direktori.
Sementara 林果 皞 dan Thomas sudah memberikan jawaban yang bagus tentang ini, saya merasa bahwa jawaban mereka lupa menjelaskan alasannya perilaku ini diterapkan di tempat pertama.
Dalam find . -deletecontoh Anda menghapus direktori saat ini terdengar sangat logis dan waras. Tapi pertimbangkan:
$ find . -name marti\*
./martin
./martin.jpg
[..]
Apakah menghapus . masih terdengar logis dan waras bagi Anda?
Menghapus direktori yang tidak kosong adalah kesalahan - jadi Anda tidak mungkin kehilangan data dengan ini find(walaupun Anda bisa melakukannya rm -r) - tetapi shell Anda akan memiliki direktori kerja saat ini ditetapkan ke direktori yang tidak ada lagi, yang menyebabkan beberapa membingungkan dan perilaku mengejutkan:
$ pwd
/home/martin/test
$ rm -r ../test
$ touch foo
touch: cannot touch 'foo': No such file or directory
Tidak menghapus direktori saat ini hanya desain antarmuka yang baik dan sesuai dengan prinsip paling tidak mengejutkan.
find . -print
,.cd ..; rm -r dir
dengan shell lain dengan semantik yang cukup jelas ...Jawaban:
Para anggota
findutils
menyadarinya , ini kompatibel dengan * BSD:The NEWS dalam kode findutils sumber menunjukkan bahwa mereka memutuskan untuk menjaga perilaku:
[MEMPERBARUI]
Karena pertanyaan ini menjadi salah satu topik hangat, jadi saya menyelami kode sumber FreeBSD dan keluar alasan yang lebih meyakinkan.
Mari kita lihat kode sumber utilitas FreeBSD :
Seperti yang Anda lihat, jika tidak menyaring titik dan titik-titik, maka itu akan mencapai
rmdir()
fungsi C yang ditentukan oleh POSIXunistd.h
.Lakukan tes sederhana, rmdir dengan argumen dot / dot-dot akan mengembalikan -1:
Mari kita lihat bagaimana POSIX menggambarkan rmdir :
Tidak ada alasan yang diberikan mengapa
shall fail
.Saya menemukan
rename
menjelaskan beberapa alasan :Jalur sistem file siklikal ?
Saya melihat-lihat Bahasa Pemrograman C (Edisi ke-2) dan mencari topik direktori, anehnya saya menemukan kodenya mirip :
Dan komentarnya!
"loop forever" , ini sama seperti
rename
menggambarkannya sebagai "jalur sistem file siklis" di atas.Saya sedikit memodifikasi kode dan membuatnya berjalan di Kali Linux berdasarkan jawaban ini :
Ayo lihat:
Ini berfungsi dengan benar, sekarang bagaimana jika saya berkomentar
continue
instruksi:Seperti yang Anda lihat, saya harus menggunakan Ctrl+ Cuntuk mematikan program loop tak terhingga ini.
Direktori '..' membaca entri pertamanya '..' dan loop selamanya.
Kesimpulan:
GNU
findutils
mencoba kompatibel denganfind
utilitas di * BSD .find
utilitas dalam * BSD secara internal menggunakanrmdir
fungsi C yang kompatibel dengan POSIX yang tidak mengizinkan dot / dot-dot.Alasan
rmdir
tidak mengizinkan dot / dot-dot adalah mencegah jalur sistem file siklis.Bahasa Pemrograman C yang ditulis oleh K&R menunjukkan contoh bagaimana dot / dot-dot akan mengarah ke program loop selamanya.
sumber
Karena
find
perintah Anda kembali.
sebagai hasilnya. Dari halaman inform
:Jadi, sepertinya
find
hanya menempel pada aturan POSIX dalam kasus ini.sumber
/var/log
dan Anda menjalankannya sebagai root, berpikir bahwa itu akan menghapus semua subdir dan juga menghapus direktori saat ini?man
halaman untukfind
mengatakan: "Jika penghapusan gagal, pesan kesalahan dikeluarkan." Mengapa tidak ada kesalahan yang dicetak?mkdir foo && cd foo && rmdir $(pwd)
. Menghapus.
(atau..
) itu tidak berhasil.Panggilan sistem rmdir gagal dengan EINVAL jika komponen terakhir dari jalur argumennya adalah
"."
. Ini didokumentasikan di http://pubs.opengroup.org/onlinepubs/009695399/functions/rmdir.html dan alasan perilaku tersebut adalah:sumber
Panggilan
rmdir(".")
sebagai panggilan sistem tidak berfungsi ketika saya mencobanya, jadi tidak ada alat level yang lebih tinggi yang dapat berhasil.Anda harus menghapus direktori melalui nama aslinya bukan
.
alias.sumber
Sementara 林果 皞 dan Thomas sudah memberikan jawaban yang bagus tentang ini, saya merasa bahwa jawaban mereka lupa menjelaskan alasannya perilaku ini diterapkan di tempat pertama.
Dalam
find . -delete
contoh Anda menghapus direktori saat ini terdengar sangat logis dan waras. Tapi pertimbangkan:Apakah menghapus
.
masih terdengar logis dan waras bagi Anda?Menghapus direktori yang tidak kosong adalah kesalahan - jadi Anda tidak mungkin kehilangan data dengan ini
find
(walaupun Anda bisa melakukannyarm -r
) - tetapi shell Anda akan memiliki direktori kerja saat ini ditetapkan ke direktori yang tidak ada lagi, yang menyebabkan beberapa membingungkan dan perilaku mengejutkan:Tidak menghapus direktori saat ini hanya desain antarmuka yang baik dan sesuai dengan prinsip paling tidak mengejutkan.
sumber