Saya bertanya-tanya apakah menggunakan rm $(ls)
untuk menghapus file (atau rm -r $(ls)
menghapus direktori juga) aman? Karena di semua situs web, orang memberikan cara lain untuk melakukan ini meskipun perintah ini tampaknya jauh lebih mudah daripada perintah lainnya.
13
touch 'foo -r .. bar'
;rm $(ls)
; kemana direktori orang tua saya pergi? Juga, apa jenis alternatif yang Anda lihat yang bahkan lebih rumit dari ini?rm *
jauh lebih mudah untuk mengetik dan memikirkannya, dan lebih aman (tetapi tidak sepenuhnya aman; lihat jawaban Dennis).ls
dapat bervariasi antara implementasi, dan karena itu tidak standar. Tergantung pada apa yang Anda butuhkan, pertimbangkan alternatif sepertifind
danstat
. Anda harus menggunakanls
hanya untuk konsumsi manusia, tidak pernah untuk digunakan oleh perintah lain atau dalam skrip.Jawaban:
Apa yang ingin dilakukan?
ls
daftar file dalam direktori saat ini$(ls)
menggantikan keluaranls
tempat yang sebagai argumen untukrm
rm $(ls)
dimaksudkan untuk menghapus semua file dalam direktori saat iniAda apa dengan gambar ini?
ls
tidak dapat menangani karakter khusus dengan benar dalam nama file. Pengguna Unix umumnya disarankan untuk menggunakan pendekatan yang berbeda . Saya juga menunjukkan hal itu dalam pertanyaan terkait tentang penghitungan nama file . Contohnya:Juga, sebagaimana disebutkan dengan tepat dalam jawaban Denis, nama file dengan tanda hubung utama, dapat ditafsirkan sebagai argumen
rm
setelah penggantian, yang mengalahkan tujuan menghapus nama file.Pekerjaan apa
Anda ingin menghapus file di direktori saat ini. Jadi gunakan glob
rm *
:Anda bisa menggunakan
find
perintah. Alat ini sering direkomendasikan untuk lebih dari sekedar direktori saat ini - ini dapat secara rekursif melintasi seluruh pohon direktori, dan beroperasi pada file melalui-exec . . .{} \;
Python tidak memiliki masalah dengan karakter khusus dalam nama file, jadi kami juga dapat menggunakannya (perhatikan bahwa ini hanya untuk file, Anda harus menggunakan
os.rmdir()
danos.path.isdir()
jika Anda ingin beroperasi pada direktori):Bahkan, perintah di atas dapat diubah menjadi fungsi atau alias
~/.bashrc
untuk singkatnya. Sebagai contoh,Versi Perl itu akan menjadi
sumber
"$(ls)"
Contoh Anda hanya berfungsi jika hanya ada satu file di direktori. Anda mungkin juga cukup menggunakan tab-completion untuk memperluas nama file karena itu satu-satunya penyelesaian.ls
:) Saya akan mengeditnya$(ls)
untuk menonaktifkan pemisahan kata, atau membiarkan pemisahan kata terjadi (dengan hasil yang merusak). Satu-satunya cara bersih untuk melewati daftar beberapa string tanpa memperlakukan data sebagai kode adalah dengan variabel array, atau dengan\0
sebagai pemisah, tetapi shell itu sendiri tidak bisa melakukan itu. MasihIFS=$'\n'
yang paling berbahaya, tetapi tidak bisa ditandingifind -print0 | xargs -0
. Ataugrep -l --null
. Atau Anda menghindari seluruh masalah dengan hal-hal sepertifind -exec rm {} +
. (Catat+
untuk memberikan beberapa argumen ke setiap permintaan rm; JAUH lebih efisien).IFS=$'\n'
akan gagal dalam kasus ini, juga, karena saya sudah baris baru dalam nama file, jadi kata-kata akan memperlakukannya sebagai dua nama file, bukan satu. Alasan anehnya, bagaimanapun, adalah fakta bahwa dengan defaultIFS
yaitu spasi, tab, baris baru, aslirm "$(ls)"
juga harus gagal, seharusnya memperlakukan seperti saya katakan nama file sebagai dua yang terpisah, tetapi tidak. Biasanya saya gunakanfind
dengan-exec
, ataufind . . .-print0 | while IFS= read -d'' FILENAME ; do . . . done
struktur untuk berurusan dengan nama file. Atau bisa digunakanpython
, saya sudah menambahkan contoh itu."$(ls)"
selalu berkembang menjadi satu arg karena kutipan melindungi perluasan dari$(ls)
pemisahan kata. Sama seperti mereka melindungi"$foo"
.Tidak, itu tidak aman, dan alternatif yang umum digunakan
rm *
tidak jauh lebih aman.Ada banyak masalah dengan
rm $(ls)
. Seperti yang sudah dibahas orang lain dalam jawaban mereka, hasil darils
akan dibagi pada karakter yang ada di pemisah bidang internal .Skenario kasus terbaik, itu tidak bekerja. Skenario kasus terburuk, Anda bermaksud menghapus hanya file (tapi bukan direktori) - atau secara selektif menghapus beberapa file
-i
- tetapi ada file dengan namac -rf
di direktori saat ini. Mari lihat apa yang terjadi.Perintah
rm -i $(ls)
itu seharusnya menghapus hanya file dan bertanya sebelum menghapus masing-masing, tetapi perintah yang akhirnya dijalankan dibacajadi itu melakukan sesuatu yang sama sekali berbeda.
Perhatikan bahwa
rm *
hanya sedikit lebih baik. Dengan struktur direktori seperti sebelumnya, itu akan berperilaku seperti yang dimaksudkan di sini, tetapi jika Anda memiliki file yang dipanggil-rf
, Anda masih kurang beruntung.Ada beberapa alternatif yang lebih baik. Yang paling mudah hanya melibatkan rm dan globbing.
Perintah
akan bekerja persis seperti yang dimaksudkan, di mana
--
sinyal bahwa segala sesuatu setelahnya tidak harus ditafsirkan sebagai opsi.Ini telah menjadi bagian dari pedoman sintaks utilitas POSIX selama lebih dari dua dekade sekarang. Ini tersebar luas, tetapi Anda seharusnya tidak mengharapkannya hadir di mana-mana.
Perintah
membuat bola berkembang secara berbeda dan karenanya tidak memerlukan dukungan dari utilitas yang disebut.
Untuk contoh saya dari atas, Anda dapat melihat perintah yang pada akhirnya akan dieksekusi oleh prepending echo .
Yang utama
./
mencegah rm dari secara tidak sengaja memperlakukan salah satu nama file seperti opsi.sumber
rm
. +1touch 'foo -rf .. bar
. Saya tidak berpikir penyerang bisa mendapatkan yang lebih tinggi dari direktori induk, kecuali kita dapat menghasilkan pemisah jalur dalamls
output.rm: refusing to remove '.' or '..' directory: skipping '..'
atau sesuatu yang serupa ketika mencoba untuk menghapus direktori induk.