Sesuatu yang saya rasa harus saya ketahui dengan pasti: jika saya ls <something>
, akan rm <something>
menghapus file yang sama persis yang ls
ditampilkan? Apakah ada keadaan di mana rm
dapat menghapus file yang ls
tidak muncul? (Ini dalam bash 18,04)
Sunting: terima kasih kepada semua orang yang menjawab. Saya pikir jawaban lengkap adalah kombinasi dari semua jawaban, jadi saya telah menerima jawaban yang paling banyak dipilih sebagai "jawaban".
Hal-hal tak terduga yang saya pelajari selama ini:
ls
tidak semudah yang Anda kira dalam penanganan argumennya- Dalam instalasi sederhana un-fiddled-with Ubuntu, .bashrc alias
ls
- Jangan beri nama file Anda dimulai dengan tanda hubung karena dapat terlihat seperti argumen perintah, dan penamaan satu -r memintanya!
rm
tidak memiliki--dry-run
bendera ...find -delete
lebih baik daripadarm
? Anda mengatakan "Itu sebabnya" , tetapi sama sekali tidak jelas bagi saya apa yang dimaksud. Juga perhatikan bahwafind
permohonan Anda akan menghapus semua file secara rekursif di direktori saat ini, di manarm
hanya akan menghapus file di direktori langsung. Juga-name *
adalah no-op. Secara keseluruhan, saya cukup bingung dengan saran Anda ...find
ini adalah karena Anda dapat menjalankannya, melihat semua file, dan kemudian menjalankan perintah yang sama dengannya-delete
. Karena Anda sudah melihat hasil darifind
, seharusnya tidak ada ambiguitas dengan apa yang akan dihapus (saya sebenarnya ingin mendengar rincian lebih lanjut tentang ini dalam bentuk jawaban)-delete
" - Tapi bagaimana itu lebih baik daripada menjalankanls <filespec>
, diikuti olehrm <filespec>
(yang OP sudah tahu bagaimana melakukannya)?find ... -print
pertama untuk mengonfirmasi file apa yang akan dihapus, dan kemudianfind ... -delete
, Anda masih akan menghapus file yang dibuat di antara kedua perintah. Jika Anda menggunakan keduanya-print
dan-delete
, Anda tidak mendapatkan konfirmasi, hanya laporan setelah fakta tentang apa yang telah dihapus (dan Anda mungkin juga menggunakannyarm -v
).Jawaban:
Baik, keduanya
ls
danrm
beroperasi pada argumen yang diteruskan kepada mereka.Argumen ini bisa berupa file sederhana, jadi
ls file.ext
danrm file.ext
beroperasi pada file yang sama dan hasilnya jelas (daftarkan file / hapus file).Jika sebaliknya argumen adalah direktori,
ls directory
daftarkan konten direktori sementararm directory
tidak akan berfungsi sebagaimana mestinya (yaiturm
tanpa flag tidak dapat menghapus direktori, sementara jika Anda melakukannyarm -r directory
, itu secara rekursif menghapus semua file di bawahdirectory
dan direktori itu sendiri ).Tetapi perlu diingat bahwa argumen baris perintah dapat dikenakan ekspansi shell , jadi tidak selalu dijamin bahwa argumen yang sama diteruskan ke kedua perintah jika mengandung wildcard, variabel, output dari perintah lain, dll.
Sebagai contoh ekstrem pikirkan
ls $(rand).txt
danrm $(rand).txt
, argumennya "sama" tetapi hasilnya sangat berbeda!sumber
ls
vs dirm *
mana ada file "tersembunyi" (dot), meskipun itu sama sekali bukan perbandingan yang adil karena saya tidak menulisls *
. Tetapirm
tidak ada artinya sendiri sehingga semuanya benar-benar apel dan jeruk. Jika saya mengerti dengan benar, itulah inti dari jawaban Anda, pekerjaan yang sangat bagus :)ls
vsrm -r
: perintahls <directory>
tidak akan menampilkan file tersembunyi di dalam direktori, tetapirm -r <directory>
akan menghapus bahkan file yang tersembunyi.ls
tidak akan mencantumkannya (kecuali jika itu dialihkan kels -a
), danrm *
tidak akan menghapusnya (kecuali jika Anda telahdotglob
menetapkan).Jika Anda memikirkan sesuatu seperti
ls foo*.txt
vs.rm foo*.txt
, maka ya, mereka akan menampilkan dan menghapus file yang sama. Shell memperluas glob, dan meneruskannya ke perintah yang dipermasalahkan, dan perintah bekerja pada file yang terdaftar. Satu daftar mereka, satu menghapusnya.Perbedaan yang jelas adalah bahwa jika ada file-file itu menjadi direktori, maka
ls
akan daftar isinya, tetapirm
akan gagal untuk menghapusnya. Itu biasanya bukan masalah, karenarm
akan menghapus kurang dari apa yang ditunjukkan olehls
.Masalah besar di sini berasal dari menjalankan
ls *
ataurm *
dalam direktori yang berisi nama file dimulai dengan tanda hubung . Mereka akan memperluas ke baris perintah dari dua program seolah-olah Anda menuliskannya sendiri, danls
akan-r
berarti "urutan urutan terbalik", sementara yangrm
akan-r
berarti penghapusan rekursif. Perbedaannya penting jika Anda memiliki subdirektori setidaknya dua level. (ls *
akan menampilkan isi dari direktori level pertama, tetapirm -r *
semuanya akan melewati sublevel pertama juga.)Untuk menghindarinya, tulis gumpalan permisif dengan
./
pengarah untuk menunjukkan direktori saat ini, dan / atau beri--
tanda pada akhir pemrosesan opsi sebelum gumpalan (yaiturm ./*
ataurm -- *
).Dengan gumpalan seperti
*.txt
, itu sebenarnya bukan masalah karena titik adalah karakter opsi yang tidak valid, dan akan menyebabkan kesalahan (sampai seseorang memperluas utilitas untuk menemukan makna untuk itu), tetapi tetap lebih aman untuk meletakkannya di./
sana.Tentu saja Anda juga bisa mendapatkan hasil yang berbeda untuk kedua perintah jika Anda mengubah opsi globbing shell, atau membuat / memindahkan / menghapus file di antara perintah, tapi saya ragu Anda berarti salah satu dari kasus-kasus itu. (Berurusan dengan file baru / yang dipindahkan akan sangat berantakan untuk dilakukan dengan aman.)
sumber
Mengesampingkan perilaku shell, mari kita fokus hanya pada apa
rm
danls
bisa berurusan dengan diri mereka sendiri. Setidaknya satu kasus di manals
akan menunjukkan apa yangrm
tidak dapat dihapus melibatkan izin direktori, dan yang lainnya - direktori khusus.
dan..
.Izin folder
rm
adalah operasi pada direktori, karena dengan menghapus file, Anda mengubah isi direktori (atau dengan kata lain daftar entri direktori, karena d irectory tidak lebih dari daftar nama file dan inode ). Ini berarti Anda perlu izin menulis di direktori. Bahkan jika Anda adalah pemilik file , tanpa izin direktori Anda tidak dapat menghapus file. The sebaliknya juga benar :rm
dapat menghapus file yang mungkin dimiliki oleh orang lain, jika Anda adalah pemilik direktori.Jadi, Anda mungkin telah membaca dan mengeksekusi izin pada direktori, yang akan memungkinkan Anda melintasi direktori dan melihat konten dengan baik, misalnya
ls /bin/echo
, tetapi Anda tidak bisarm /bin/echo
kecuali Anda adalah pemilik/bin
atau meningkatkan hak istimewa Anda bersamasudo
.Dan Anda akan melihat kasus seperti ini di mana-mana. Inilah satu kasusnya: https://superuser.com/a/331124/418028
Direktori khusus '.' dan '..'
Kasus khusus lainnya adalah
.
dan..
direktori. Jika Anda melakukannyals .
atauls ..
, itu akan dengan senang hati menunjukkan kepada Anda kontennya, tetapirm
mereka tidak diizinkan:sumber
Jika Anda mengetik
ls *
dan kemudianrm *
, ada kemungkinan Anda akan menghapus lebih banyak file dari yangls
diperlihatkan - mereka mungkin telah dibuat dalam interval waktu yang sangat kecil antara akhirls
dan awalrm
.sumber
/tmp
, di mana banyak aplikasi dapat membuat file sementara, sehingga selalu ada kemungkinan di kedua perintah dengan*
. Namun, beberapa aplikasi juga membuat file anonim denganunlink()
menyimpannya sambil menjaga agar pegangan file tetap terbuka, sehingga file tersebut dapat ditampilkanls *
tetapirm *
tidak dapat ditangkap.*
ada perbedaan antara apa yangls
akan ditampilkan dan apa yangrm
beroperasi, karena daftar isi direktori telah berubah di antaranya.ls *
sebenarnya bisa menunjukkan nama file yang sudah hilang.ls *
danrm *
tidak bertanggung jawab untuk memperluas gumpalan - yang dilakukan oleh shell sebelum meneruskannya ke perintah.Ini berarti bahwa Anda dapat menggunakan perintah apa pun dengan daftar file yang diperluas - jadi saya akan menggunakan sesuatu yang sesedikit mungkin.
Jadi cara yang lebih baik untuk melakukan ini (atau setidaknya, cara lain) adalah dengan melewati perantara.
echo *
akan menunjukkan kepada Anda apa yang akan diteruskan kerm
perintah Anda .sumber
printf "%s\n" *
untuk mendapatkan tampilan yang jelas tentang nama file dengan spasi. (Atau%q
sebaliknya untuk berurusan dengan baris baru dan karakter kontrol juga, dengan mengorbankan output yang lebih buruk.)Bagaimana tentang:
Pada dasarnya wildcard berkembang ke hal-hal yang dimulai dengan
-
(atau hal-hal yang dimasukkan secara manual dimulai dengan-
tetapi yang terlihat sedikit lebih seperti curang) dapat ditafsirkan secara berbeda olehls
danrm
.sumber
Ada yang kasus di mana tepi apa yang
ls
menunjukkan tidak aparm
menghilangkan. Yang agak ekstrem, tapi untungnya tidak berbahaya adalah jika argumen yang Anda berikan adalah tautan simbolis ke direktori:ls
akan menunjukkan kepada Anda semua file di direktori symlink, sementararm
akan menghapus symlink, meninggalkan direktori asli dan isinya tidak tersentuh:sumber
ln -s $HOME some_link; ls some_link
outputsome_link@
untuk saya, tetapi saya telahls
aliasls -F
. Rupanya,-F
mengubah perilaku untuk menampilkan tautan alih-alih mendereferensinya. Tidak menyangka itu.ls -l
misalnya target link, bukan tujuan ... ada harus cara untuk memeriksa link itu sendiri.ls
danrm
.ls some_link/
,,ls -H some_link
atauls -L some_link
, itu akan mendaftar direktori tertaut ke, bahkan jika Anda menambahkan-F
atau-l
. Sebaliknya (sort-of),-d
mengatakan melihat direktori daripada isinya; bandingkanls -l /tmp
danls -ld /tmp
.ls
. Anda pada dasarnya menunjukkan mengapa menghitung perilaku dengan bendera yang berbeda tidak layak untuk pertanyaan ini ...Jika Anda hanya melakukan
ls
alih-alihls -a
, yarm
dapat menghapus file tersembunyi yang belum Anda lihatls
tanpa-a
.Contoh:
Menurut :
ls dir_test
: hanya akan menampilkan test2ls -A dir_test
: akan menampilkan test2 + .testrm -r dir_test
: akan menghapus semua (.test + test2)Saya harap itu akan membantu Anda.
sumber
rm *
tidak akan menghapus file dot. Jika ya,ls *
juga akan menunjukkan kepada mereka.ls *
jangan tampilkan file tersembunyi.ls -a
akan daftar.
,..
,.test
dantest2
. Anda mungkin ingin mengubah contoh untuk digunakanls -A
, yang mencantumkan semuanya kecuali.
dan..
(yaitu, hanya.test
dantest2
).Sudah ada banyak jawaban bagus, tetapi saya ingin menambahkan beberapa wawasan yang lebih dalam.
Tanyakan kepada diri Anda pertanyaan: Berapa banyak parameter dilewatkan ke
ls
, jika Anda menulis...? Perhatikan bahwa
ls
perintah tidak mendapatkan*
parameter sebagai jika ada file yang*
dapat diperluas. Sebagai gantinya, shell pertama-tama melakukan globbing sebelum menjalankan perintah, jadils
perintah sebenarnya mendapatkan banyak parameter karena ada file yang cocok dengan globbing. Untuk menekan globbing, kutip parameternya.Hal ini berlaku untuk setiap perintah:
echo *
vsecho '*'
.Ada skrip, panggil saja
countparams.sh
untuk menguji efeknya. Ini memberi tahu Anda berapa banyak parameter yang dilewati dan mencantumkannya.Jadikan itu dapat dijalankan dan dijalankan
./countparams.sh *
. Belajar dari hasilnya!sumber
Glob akan berkembang dengan cara yang sama di kedua kali, jika isi direktori sama pada dua waktu yang berbeda.
Jika Anda benar-benar ingin memeriksa apa yang akan dihapus, gunakan
rm -i *.txt
. Ini akan meminta Anda secara terpisah untuk setiap file sebelum (mencoba) menghapusnya.Ini dijamin aman terhadap kondisi balapan:
ls *.txt
/ file baru dibuat /rm *.txt
karena Anda diminta untuk setiap file oleh program yang sama yang melakukan penghapusan.
Ini terlalu rumit untuk penggunaan normal, dan jika Anda
rm
inginrm -i
, Anda akan menemukan diri Anda menggunakan\rm
ataurm -f
cukup sering. Tetapi perlu setidaknya disebutkan bahwa ada solusi untuk kondisi balapan. (Bahkan portabel untuk sistem non-GNU: POSIXrm(1)
menentukan-i
opsi .)Opsi lain adalah bash array:,
to_remove=(*.txt)
lalu minta pengguna untuk mengonfirmasi (mungkin setelah melakukanls -ld -- "${to_remove[@]}"
), lalurm -- "${to_remove[@]}"
. Jadi ekspansi glob hanya dilakukan sekali, dan daftar dilewatkan secara verbatim kerm
.Opsi praktis lain yang dapat digunakan adalah GNU
rm -I
( halaman manual ), yang meminta jika menghapus lebih dari 4 item. (Tapi tidak menunjukkan daftar, hanya total.) Saya gunakanalias rm='rm -I'
di desktop saya.Ini adalah perlindungan yang bagus terhadap kembalinya jari gemuk dengan pola setengah mengetik yang terlalu cocok. Tetapi menggunakan yang
ls
pertama umumnya baik di direktori yang Anda miliki, atau pada sistem pengguna tunggal, dan ketika tidak ada proses latar belakang yang secara asinkron dapat membuat file baru di sana. Untuk menjaga agar tidak main jari, jangan mengetikrm -rf /foo/bar/baz
dari kiri ke kanan.rm -rf /
adalah kasus khusus, tetapirm -rf /usr
tidak! Biarkan-rf
bagian itu, atau mulai denganls
, dan hanya tambahkanrm -rf
bagian setelah mengetik lintasan.sumber