Mengapa `cp` dan` rm` memperlakukan direktori secara terpisah?

10

Mengapa alat menyukai cpdan rmmemperlakukan direktori secara terpisah dari file biasa? Mereka berdua mengharuskan pengguna untuk secara eksplisit menentukan dia menginginkan perilaku rekursif, atau mereka tidak akan berurusan dengan direktori sama sekali.

Interaksi pertama saya (beberapa waktu lalu) dengan komputer adalah pada lingkungan Windows / GUI / point-and-click / drag-and-drop, selalu tampak wajar bahwa operasi ini akan berperilaku sama, terlepas dari target.

Perilaku ini khususnya membuat saya frustrasi ketika saya memberikan perintah dengan wildcard. Bagaimana jika saya ingin menghapus semua yang ada di direktori ( *) kecuali untuk subdir yang tidak kosong ?

Saya hanya bisa membayangkan bahwa ini adalah semacam fitur keamanan untuk mencegah pengguna menembak dirinya sendiri, tetapi ini bertentangan dengan pemahaman saya tentang beberapa prinsip Unix:

  • Unix biasanya tidak melindungi pengguna dari dirinya sendiri. Selalu diasumsikan pengguna tahu apa yang dia lakukan.
  • Untuk Unix semuanya adalah file. Bukankah direktori hanyalah file lain? Mengapa mereka diperlakukan berbeda?

Pertanyaan saya:

  • Apakah perilaku ini berasal dari keterbatasan teknis atau itu pilihan yang disengaja?

Dan dalam kasus yang terakhir,

  • Adakah kisah historis tentang alasan yang memotivasi pilihan ini?
rahmu
sumber
Untuk rmsetidaknya, jika Anda ingin mengabaikan perbedaan antara file dan direktori, Anda dapat menempatkan dalam Anda ~/.bashrcberkas: alias rm='rm -r'.
BenjiWiebe
1
Lihat juga pertanyaan yang berbeda namun terkait, unix.stackexchange.com/questions/46066/…
derobert
1
Anda tidak dapat membandingkan cp dan rm dengan manajer file windows. Mulai cmd.exe dan coba salin dan hapus dan bandingkan perilaku.
ott--

Jawaban:

11

Derobert's Mengapa program unix mv tidak memerlukan opsi -R (rekursif) untuk direktori tetapi cp memang membutuhkannya? pada dasarnya menjawab pertanyaan Anda: menyalin atau menghapus file biasa berbeda dari melakukan operasi yang sama dengan direktori, karena untuk direktori Anda harus memproses semua file yang terkandung di dalamnya. Karenanya operasinya berbeda secara mendasar.

Yang juga perlu diperhatikan adalah bahwa ada utilitas khusus rmdiryang hanya dapat bertindak pada direktori kosong. Tanpa memeriksa fakta-fakta ini menyebabkan orang menyimpulkan bahwa mungkin awalnya rmhanya mampu menghapus non-direktori dan penghapusan mendalam harus dicapai dengan menggunakan secara rekursif menggunakan rmdirektori kosong dan kemudian rmdirmenghapusnya.

peterph
sumber
rmdirjuga nama panggilan sistem yang digunakan untuk menghapus direktori. Direktori harus kosong untuk pemanggilan sistem, dan utilitas dengan nama yang sama hanya "front-end", mirip dengan unlinkperintah dan utilitas.
jordanm
Tepat - itulah yang membuat saya percaya bahwa awalnya rmmungkin tidak dapat menghapus direktori sama sekali (karena utilitas baris perintah seringkali hanya pembungkus yang relatif sederhana di sekitar syscalls).
peterph
Judul pertanyaan saya mungkin menyesatkan untuk berpikir saya bertanya tentang rincian teknis. Saya bertanya apakah itu pilihan yang disengaja. Saya ingin tahu apakah saya satu-satunya yang berpikir bahwa dari sudut pandang pengguna akhir perilaku ini tidak konsisten. Saya menerima jawaban Anda karena itu secara tidak langsung menjawab pertanyaan saya: keterbatasan teknis di internal Unix (pada tingkat syscall) tampaknya menjadi asal dari perilaku ini, dan warisan mungkin mencegah kita melakukan hal itu dengan cara lain hari ini. Bukankah "pembungkus sederhana di sekitar syscalls" seharusnya memberi kita perilaku yang lebih cerdas?
rahmu
2
Dari POV pengguna akhir, tampaknya memang aneh, tetapi Anda sebenarnya bertanya tentang alasannya. :) Adapun pembungkus - itu semua tergantung pada seberapa "sederhana" mereka (dan apa yang Anda masih ingin menyebutnya "sederhana"). Modern rmjelas bukan hanya pembungkus sederhana (ia dapat menghapus file sekaligus sekaligus direktori). Jika Anda tidak suka memberikan -ropsi, gunakan fungsi aliasing dari shell Anda atau buat pembungkus Anda sendiri yang akan meletakkannya (yang akan lebih lambat, tetapi terlepas dari shell yang Anda gunakan).
peterph
2

Dalam beberapa rasa UNIX, halaman manual rm menentukannya sebagai perintah untuk memutuskan tautan file.
Di UNIX, file adalah objek dalam sistem file yang disebut Inodes, tanpa nama atau lokasi terpisah dari ID di sistem file. Nama mereka adalah rujukan ke mereka dalam berbagai direktori, yang merupakan jenis file yang mengindeks file (atau direktori, karena mereka adalah file) yang terdaftar di dalamnya.
Ketika menghapus tautan file, jumlah referensi file berkurang, dan ketika mencapai 0, sebenarnya dihapus, karena ditandai sebagai bebas oleh sistem file dan blok / luasannya juga ditandai bebas.

Jika Anda memiliki kemampuan untuk rm direktori tanpa memutuskan file di dalamnya terlebih dahulu, Anda akan mencapai titik di mana Anda memiliki inode yang dirujuk dalam sistem file Anda tetapi tidak dapat diakses dengan cara biasa.
Karena ada referensi kepada mereka sesuai dengan jumlah referensi mereka, mereka tidak ditandai sebagai dihapus dan menjadi file yang hilang.
Ini menjadi lebih kompleks ketika "file" yang hilang adalah direktori, dan dengan demikian meningkatkan jumlah potensi penyimpanan yang hilang dalam sistem file.

Jadi rm -r ditambahkan, sebagai fitur untuk memudahkan kehidupan pengguna UNIX, dengan mengorbankan standar "semangat UNIX", karena lebih kompleks daripada utilitas UNIX klasik karena turun ke direktori dan menghapus file di dalam,

Selain itu, pada awal UNIX, sistem tidak memiliki banyak memori, dan pemetaan struktur rekursif direktori memang memiliki penalti kinerja, dan kadang-kadang tidak mungkin dilakukan tanpa memecah pekerjaan.

cp, membaca file dan menyalinnya, blok demi blok. Jika ingin menyalin direktori sama seperti file, itu akan menambah referensi ke file di dalam tanpa meningkatkan jumlah referensi mereka, yang dapat menyebabkan data tidak konsisten (jika membaca / menulis ke inode yang blok ditandai bebas sejak mereka inode asli telah dihapus), kehilangan data - karena menghapus referensi (diketahui) terakhir ke file dapat menyebabkan nomor inode itu untuk didaur ulang.

Untuk tl; kerumunan dr:
Direktori di UNIX adalah jenis file, itu benar, tetapi karena informasi di dalamnya diperlakukan secara berbeda oleh sistem, karena merupakan metadata dari sistem file, perintah yang memanipulasi file tidak dapat bekerja pada direktori tanpa mengubah perilaku mereka untuk memanipulasi metadata dependen juga.

Didi Kohen
sumber