Cegah pengguna mengetikkan ruang tidak sengaja antara rm dan wildcard

29

Niat:

rm -rf string*

Masalah:

rm -rf string *

Kasus pertama adalah penggunaan rm yang sah dan umum, kesalahan ketik kecil dapat menyebabkan banyak masalah dalam kasus kedua. Apakah ada cara sederhana untuk secara cerdas melindungi terhadap trailing yang tidak disengaja atau wildcard terkemuka?

bobdole
sumber
8
Dengan shell yang baru-baru ini dikonfigurasi dengan baik ( zshatau bash) saya lebih suka membiasakan menekan tombol tab (untuk memicu pelengkapan otomatis) sebelum menekan tombol kembali
Basile Starynkevitch
2
touch -- -iakan membuat file -iyang akan diteruskan ke rmsebagai parameter -isaat Anda memasukkan wildcard dalam argumen Anda.
Pasang kembali Monica - M. Schröder
@ MartinSchröder: Jika Anda berada di direktori tempat file itu berada.
Dijeda sampai pemberitahuan lebih lanjut.
@ MartinSchröder Itu hanya akan berfungsi jika Anda mengetik rm *. Jika Anda mengetik rm name *, itu akan diperluas ke rm name -i other names. -itidak akan diproses sebagai opsi karena ini bukan sebelum nama file.
Barmar
1
Biasanya, pengguna hanya melakukan ini sekali.
tedder42

Jawaban:

37

Sebuah DEBUGperangkap dapat ditulis untuk membatalkan perintah yang terlihat mencurigakan. Berikut ini, atau kode yang mirip dengannya, dapat ditambahkan ke Anda ~/.bashrc:

shopt -s extdebug
checkcommand() {
  if [[ $BASH_COMMAND = 'rm -r'*' *' ]]; then
    echo "Suppressing rm -r command ending in a wildcard" >&2
    return 1
  fi
  # check for other commands here, if you like
  return 0
}
trap checkcommand DEBUG

Sesuaikan logika sesuai selera.

(Saya sebenarnya tidak berharap pendekatan ini bermanfaat - terlalu banyak cara untuk mengacaukan perintah secara destruktif untuk menemukan mereka menguji satu-per-satu - tetapi ini memberikan jawaban literal untuk pertanyaan itu).

Charles Duffy
sumber
47

Tidak ada cara untuk sistem yang benar-benar anti peluru. Dan menambahkan "Apakah Anda yakin?" meminta hal-hal yang kontraproduktif dan mengarah ke "Tentu saja saya yakin." reaksi kneejerk.

Trik yang saya ambil dari buku di tahun-tahun yang lalu adalah dengan pertama-tama melakukannya ls -R blah*, lakukan rm -fr blah* jika dan hanya jika daftar yang muncul mengenai apa yang saya inginkan.

Cukup mudah untuk melakukan lsperintah terlebih dahulu, lalu hapus ls -Rdan ganti dengan rm -fr.

Pertanyaan terakhir adalah, "Jika informasi itu berharga bagi Anda, di mana cadangan Anda?"

pembunuh kulit
sumber
4
Daripada panah ke atas, Anda dapat menggunakan ^ls -R^rm -rf^dan mungkin menetapkan sebagai alias
exussum
FWIW, inilah ls -Ryang pada dasarnya saya lakukan sepanjang waktu, tetapi begitu insting pada titik ini sehingga menyelinap di pikiran sadar saya ketika saya dibentuk oleh jawaban. Jadi +1 untuk itu.
JakeGould
Ini juga memiliki keuntungan yang tidak akan membahayakan jika Anda menabrak tombol masuk, atau menabrak mouse Anda dan menempelkan sesuatu dengan baris baru. Kadang-kadang saya memasukkan hal-hal dalam urutan yang kurang efisien hanya untuk keamanan yang lebih, misalnya cat > .log, kemudian masuk kembali dan rekatkan atau tarik nama file sebelum .log. Jadi, tidak ada titik yang saya miliki > valuablefiledi cmdline.
Peter Cordes
Saya menggunakan rm alias rm -i, jadi saya sering hanya menulis perintah rm saya dan kemudian meletakkan \ di awal baris. ( \rmmenghindari alias-ekspansi untuk rm, karena sebagian kata dikutip). Jika saya membutuhkan -ratau -f, ya saya kadang-kadang mulai dengan lsbukannya rm, atau hanya meninggalkan -rfbagian. (sunting, bagaimana Anda mendapatkan pemformatan kode backslash? bquote bslash bslash bquote gagal.
Peter Cordes
8

Bisakah Anda melatih diri untuk menggunakan, katakanlah, rmrfsebagai pengganti rm -rf?

Jika demikian, fungsi bash ini akan memberi Anda kesempatan untuk melihat apa yang sebenarnya terjadi sebelum mengonfirmasi perintah:

rmrf() { echo rm -rf "$@"; read -p "Proceed (y/N)? "; [ "${REPLY,,}" = y ] && rm -rf "$@"; }

Untuk membuat fungsi ini permanen, tambahkan baris ini ke ~/.bashrcfile di setiap komputer yang Anda gunakan.

Perbandingan dengan rmalias umum

Adalah umum untuk mendefinisikan alias:

alias rm='rm -i'

Ini memiliki dua batasan:

  1. Jika Anda bergantung pada alias ini, maka Anda akan kaget ketika Anda menggunakan mesin atau di lingkungan yang tidak memilikinya. Sebaliknya, mencoba menjalankan rmrfmesin tanpa fungsi itu akan menghasilkan yang tidak berbahaya command not found.

  2. Alias ​​ini tidak membantu dalam kasus Anda karena -fopsi yang Anda berikan pada baris perintah mengabaikan -iopsi di alias.

John1024
sumber
4
Bukan ide yang buruk. Tetapi itu tergantung pada fungsi ini yang diinstal dan tersedia pada sistem apa pun yang digunakan oleh pengguna ini. Jadi katakanlah mereka masuk ke server jauh untuk beberapa pekerjaan dan menjalankan rm -rfperintah yang salah , apa yang terjadi? Menciptakan fungsi pseudo seperti ini pada akhirnya hanya mempersulit solusi sederhana: Hanya lebih berhati-hati dan pahami apa itu perizinan.
JakeGould
4
@ JakeGould Dan jangan gunakan rm -f kecuali Anda benar-benar perlu .
CVn
1
Mengapa repot-repot dengan rmrf, bukannya hanya membuat fungsi shell rmyang memeriksa argumen -ratau -rf, dan memberlakukan logika khusus dalam kasus itu, jika tidak secara langsung memanggil command rm "$@"untuk memanggil rmperintah yang sebenarnya ?
Charles Duffy
3
Anda menggunakan nama yang berbeda sehingga Anda tidak menembak kaki sendiri saat penggantian Anda tidak ada. Dan saya setuju dengan @ MichaelKjörling, Anda tidak perlu -fjika tidak punya -i. Meninggalkan -fmemberi Anda peringatan ekstra sebelum menghapus file yang hanya bisa dibaca, misalnya.
Peter Cordes
6

Jika saya dalam situasi di mana menghapus file yang salah adalah benar-benar besar, salah satu hal yang telah saya lakukan yaitu membuat folder sampah, seperti mkdir trashcan, dan kemudian saya memiliki script rmTrashcanyang memiliki rm -rf trashcan/*atau rm -rf *atau serupa, ditulis sangat hati-hati dan diperiksa beberapa kali.

Dengan begitu, jika saya melakukan kesalahan, kesalahan ada pada mvperintah, bukan rmperintah. Setelah saya melakukan lsdan saya yakin persis apa yang saya menghapus, sebuah rmTrashcansebenarnya pekerjaan kotor aman.

Itu juga sangat nyaman untuk situasi di mana saya harus menghapus cadangan. Saya dapat mvsatu bulan cadangan ke tempat sampah, mvbeberapa yang ingin saya simpan (1 bulan, 15 bulan) kembali ke cadangan, lalu rmTranshcansisanya. Melakukan perintah yang sama sulit dilakukan dengan rmsendirinya, dan melakukannya dengan cara ini, biarkan saya lsmembuat cadangan untuk yakin dengan file apa yang saya tinggalkan (daripada hanya menghitung file yang ingin saya hapus)

Cort Ammon - Pulihkan Monica
sumber
4

Alih-alih repot dengan dua perintah ( lsdan rm), saya pikir cara yang lebih sederhana dan lebih mudah adalah dengan menggunakan find:

find . -maxdepth 1 -name "string*" -delete

Jika Anda secara tidak sengaja mengetiknya "string *"akan menghapus file bernama string charsdan string letters(yang memang Anda inginkan), tetapi itu tidak akan mengambil setiap file seperti *di shell.

Selain itu, Anda dapat mengabaikan -deleteuntuk melihat file mana yang akan dihapus, lalu tekan panah dan ketik -deletelebih mudah daripada mengetik ^ls -R^rm -rfatau omong kosong lainnya.

pengasuh
sumber
A findakan melakukan pencarian bersarang untuk file yang cocok bukan hanya parameter eksplisit yang dinyatakan pada commandline. Saya pikir ini meleset dari sasaran. Saya bisa saja salah.
Pembunuh binatang
3

Apakah ada cara sederhana untuk secara cerdas melindungi terhadap trailing yang tidak disengaja atau wildcard terkemuka?

Tidak juga. Itu diusulkan dalam jawaban lain Anda bisa membuat perintah kustom untuk menambahkan prompt sebelum menjalankan tugas. Tetapi masalah dengan perintah khusus ini adalah harus diinstal secara sadar pada sistem yang sedang Anda kerjakan. Dan bahkan jika itu diinstal, masalahnya adalah refleks Anda untuk memukul yuntuk menyelesaikan tugas bisa ikut bermain.

Berarti ini semua adalah masalah antarmuka pengguna bahkan jika itu pada tingkat baris teks / perintah. Berapa banyak jaring pengaman yang Anda harapkan untuk melindungi Anda dari melakukan sesuatu yang seharusnya tidak Anda lakukan? Ini seperti gunting: Jika Anda lalai dan terpeleset dan memotong tangan Anda saat bermaksud memotong kain atau kertas, siapa yang salah? Atau bahkan lampu lalu lintas dan rambu berhenti: Tidak ada yang menghentikan pengemudi untuk menyalakan lampu atau mengabaikan rambu lalu lintas selain kesadaran akut tentang apa yang mungkin terjadi jika mereka melakukan perilaku berisiko seperti itu.

Yang mengatakan, solusi realistis terbaik terletak pada izin sistem untuk pengguna maupun kelompok. Itu adalah jaring pengaman terbaik / hanya nyata untuk melindungi pengguna dari diri mereka sendiri.

Jika Anda bekerja pada suatu sistem di mana Anda adalah satu-satunya yang mengaksesnya, Anda mungkin tergoda untuk chmod 777segalanya, tetapi itu bukan cara pengaturan sistem yang rasional. Sebaliknya izin harus berupa sesuatu 755untuk semua direktori dan 644untuk semua file yang tidak dapat dieksekusi. 755Setidaknya file yang dapat dieksekusi , tetapi mungkin bahkan 744jika Anda hanya ingin orang lain membaca tetapi tidak menjalankan file.

JakeGould
sumber
2

Coba buat rmperintah awal Anda tanpa -ftanda, tetapi -isebaliknya, yang rmakan meminta Anda untuk setiap file yang ingin dihapus. Untuk penghapusan rekursif kecil, Anda dapat menahan ytombol, setelah Anda yakin perintah telah diketik dengan benar. Untuk penghapusan besar, Anda dapat membatalkan operasi, dan menggunakan riwayat baris perintah -iuntuk dengan hati-hati mengubah ke a -f.

Nevin Williams
sumber
Anda benar-benar harus menekan y[RETURN]setiap file, tidak ada yang dapat Anda tahan dengan GNU rm. Mengedit -iadalah cara untuk pergi, setelah Anda mengetik perintah dengan benar. Kemudian Anda mendapatkan prompt hanya pada file read-only, dan mungkin hal-hal lain.
Peter Cordes
1
Cukup gunakan rm -Isehingga itu hanya meminta sekali, dan hanya untuk penghapusan yang berpotensi berbahaya (yaitu dari banyak file.)
Nick Matteo
1
Dalam forum yang kurang konstruktif, jawaban saya akan menjadi sesuatu di sepanjang baris "Jika pengetikan / pengoreksian Anda seburuk itu, Anda tidak perlu menggunakan 'rm -rf' dengan wildcard." Saya tidak tahu tentang saklar -S ... harus dimasukkan <20 tahun yang lalu; Tapi terakhir kali aku melakukan 'man rm'. :)
Nevin Williams
2

rm memiliki -idan -Imenandai untuk mengonfirmasi sebelum setiap penghapusan. Di masa lalu, beberapa distribusi telah mengaktifkannya secara default. Ini ide yang buruk. Berikan terlalu banyak dialog konfirmasi kepada pengguna untuk operasi normal dan mereka akan mulai mengkonfirmasinya. Ini hanya menggeser persyaratan untuk "hati-hati" (selalu bendera merah) ke dialog baru dan lebih menjengkelkan. "Ya. Ya. Ya. Ya! Ya Tuhan! Sial, komputer bodoh hapus saja file YESYESYESYESYES - BURUK SAYA TIDAK MAU! NOOOOOOO!" Ini adalah masalah dialog "Ya, tapi saya maksud tidak". Jawaban ini memberikan penjelasan visual tentang mengapa dialog konfirmasi datang pada waktu yang salah.

Jenis kesalahan yang Anda menggambarkan adalah tergelincir , "kinerja dari suatu tindakan yang tidak apa yang dimaksudkan". Pengguna biasanya segera mengenali kesalahan dan tahu persis bagaimana memperbaikinya. Sayangnya, Unix tidak memberikan kesempatan kepada pengguna, rm segera menghapus file. Setiap sistem operasi lain menyelesaikan masalah ini dengan membiarkan penghapusan dibatalkan, setidaknya untuk sementara waktu, dengan menggunakan Sampah.

Ada berbagai sistem sampah untuk Unix, dan jawaban ini penuh dengan saran .

Pertanyaannya adalah untuk alias rm atau tidak ke alias rm. Pro ke aliasing rm ...

  1. Anda tidak dapat membuat kesalahan dengan lupa untuk menggunakan alternatif rm.

Kontra untuk rm aliasing ...

  1. Anda mungkin mengandalkannya pada sistem yang tidak memilikinya.
  2. Mungkin menyebabkan masalah ketika disk hampir penuh.
  3. Butuh infrastruktur untuk mengosongkan sampah secara berkala.
  4. Harus memastikan untuk tidak mengganggu perilaku yang diharapkan dari rm dalam program.
  5. Mungkin tidak sepenuhnya meniru rm.

Jika Anda mengikuti argumen pertama terlalu jauh, Anda akhirnya menggunakan vi (bukan vim, vi), csh (bukan tcsh, csh) dan utilitas kuno lainnya karena semuanya tersedia secara universal. Namun, ada bahaya menyesuaikan lingkungan Anda secara berlebihan. Saya lebih suka membawa utilitas saya dan membuatnya semudah mungkin. YMMV.

Dua dan tiga adalah masalah teknis. Mereka dapat diselesaikan dengan pekerjaan penuai cerdik yang memeriksa ukuran sampah dan secara berkala membersihkan semuanya, mirip dengan tmpreaper . Ini bisa berupa pekerjaan cron, atau versi yang lebih pintar dapat menggunakan berbagai infrastruktur acara sistem file yang tersedia di banyak distribusi Linux desktop. Ini tidak sederhana, dan bahkan lebih sulit untuk dilakukan secara efisien. Lebih baik menemukan sistem yang ada daripada mencoba membuatnya sendiri.

Yang keempat dapat ditangani dengan membuat rm alias shell baru Anda alias rm='trash', maka itu tidak akan mempengaruhi program.

Kelima adalah masalah yang saya tinggalkan untuk diselesaikan pembaca. rm tidak memiliki banyak sakelar.

Schwern
sumber
Saya rm alias rm -i, tetapi saya sering menggunakan \rmuntuk mendapatkan perilaku yang tidak berubah. Saya mengetik rm -ikapan saja saya berencana untuk mengatakan tidak pada salah satu argumen. Saya terkadang memulai perintah dengan lssebagai perintah, lalu hanya memasukkan \ rm ketika saya selesai. Jadi tidak mungkin saya secara tidak sengaja dapat memukul balik rm -rf /sebagai ganti/.../file
Peter Cordes
rm -Iatau rm --interactive=oncejauh, jauh lebih menjengkelkan daripada rm -i, dan masih menangkap sesuatu yang berbahaya (hanya meminta ketika ada lebih dari 3 file, atau jika itu bersifat rekursif, dan hanya SEKALI bukannya UNTUK SETIAP FILE.)
Nick Matteo
@ Koror Ya, dan itu tidak mengubah persamaan. Mungkin membuatnya lebih mungkin pengguna akan mengabaikannya. Pengguna memiliki tujuan: menghapus barang. Prompt mengatakan "Anda yakin ingin menghapus hal-hal yang baru saja Anda suruh saya hapus?" Pengguna masih terpaku pada tujuan menghapus hal-hal, tidak memverifikasi apa yang akan dihapus, sehingga mereka mengatakan "ya" tanpa berpikir. -imungkin memberi pengguna waktu untuk mengubah tujuan. Jawaban ini pada pertanyaan terkait menjabarkan semuanya.
Schwern
@ Schwern: tetapi tidak ada yang bisa hidup rm -ilebih dari 30 detik tanpa mematikannya. Sedangkan rm -Ihanya meminta ketika kemungkinan Anda telah mengacau; prompt hanya muncul untuk penghapusan besar. Ketika Anda mencoba untuk menghapus beberapa hal dan prompt diberikan, Anda terkejut dan menyadari bahwa Anda secara tidak sengaja mengetik "foo *".
Nick Matteo
@Kundor Menghapus lebih dari tiga file dan menghapus secara rekursif (konfirmasi dinonaktifkan oleh kebiasaan yang -rfbaru saja saya temukan) adalah proxy yang buruk untuk mendeteksi kemungkinan kekacauan. Ingin menghapus sub-direktori bukan merupakan suatu kesalahan. Pesan itu tidak membantu karena itu hanya mengkonfirmasi apa yang dikatakan pengguna untuk dilakukan tanpa menambahkan informasi yang berguna pada saat pengguna tidak ingin memverifikasi. "rm: hapus 1 argumen secara rekursif?" "Ya, hapus direktori, aku baru saja memberitahumu untuk melakukan itu! ... tunggu, direktori mana itu? CRAP !!!"
Schwern
2

Saya mengajar semua orang tentang !$argumen = terakhir dalam trik perintah terakhir:

% ls job[XYZ].*
jobX.out1
jobX.out2
[rest of the matches]

% rm !$

Ini memungkinkan inspeksi ekspansi wildcard, dan kemudian menggunakan pola glob yang sama persis tanpa kemungkinan memasukkan spasi sebelum *.

Saya juga menyarankan orang tidak pernah memotong dan menempelkan pola wildcard globbing pada baris perintah yang berpotensi merusak. Karena di tangan saya sendiri itu sudah menjadi masalah :)

Seorang teknisi di lab saya baru saja membuat kesalahan ini minggu lalu (3 bulan kerja) - dan ya kami punya cadangan (1 hari di belakang).

kael
sumber
0

Semua orang tampaknya mengatakan, "Lebih berhati-hati", "Jangan membuat alias / konfirmasi segera karena Anda akan terbiasa untuk tidak memperhatikannya dengan benar".

Keren, dan semuanya. Maksud saya, saya tidak berpikir Anda harus membuat alias untuk rm(atau rmrf, karena Anda dapat dengan mudah mengacaukannya dan mengetik perintah yang sebenarnya).

Tetapi mengapa Anda tidak dapat membuat alias / skrip dan menyebutnya, katakan, removedan hanya beri satu argumen (mis. $ 1)? Wildcard harus $ 2, karena ruang yang tidak disengaja (amiright?) Dan dengan demikian skrip / wrapper / alias Anda tidak akan diberi makan yang kedua. Ya, Anda hanya dapat melakukan satu set penghapusan (dengan wildcard) sekaligus, tapi itulah harga yang akan Anda bayar.

Jika saya menulis sesuatu yang bagus, saya mungkin akan memberi tahu saya jumlah file dan direktori yang ingin dihapus, dan ukuran total barang yang saya hapus, dan kemudian meminta konfirmasi, tetapi itu mungkin menghambat aliran Anda. Mungkin menjadikan itu opsi bendera pada remove? (-saya). Anda mungkin juga ingin melakukan cek $ 1 untuk melihat apakah itu hanya wildcard tunggal dan meminta konfirmasi, dan daftar direktori tempat Anda sebenarnya.


Selain itu, ada sejumlah rmpenggantian di luar sana. Banyak yang mencoba untuk memenuhi standar desktop UI. Beberapa dari mereka mungkin layak untuk dilihat.

pengguna3082
sumber
6
Alias ​​"hapus" Anda tidak akan pernah menghapus lebih dari satu file sekaligus. Anda tidak dapat menggunakan wildcard, karena shell mengekspansinya sebelum perintah melihatnya.
Nyanyian pujian
Jadi lakukan eval padanya, lalu tarik itu ke dalam skrip?
user3082
Jadi, Anda ingin mengetik remove \*? Jika skrip Anda memungkinkan shell glob-memperluas inputnya, saya tidak melihatnya banyak membantu.
Peter Cordes
0

Trik yang sangat sederhana adalah dengan meletakkannya -rfdi akhir: rm whatever* -rf
Ini mengurangi tingkat kesalahan secara drastis, karena Anda mengetik lebih banyak karakter setelahnya *, sehingga Anda memiliki lebih banyak waktu untuk melihat kesalahan ketik.
Ini tidak menyelesaikan segalanya. Hanya trik sehari-hari yang sederhana.

Gregory MOUSSAT
sumber