Pertanyaan Apa yang 'set -e' lakukan, dan mengapa itu dianggap berbahaya?


Pertanyaan ini muncul di kuis pra-wawancara dan itu membuat saya gila. Adakah yang bisa menjawab ini dan membuat saya nyaman? Kuis tidak memiliki referensi ke shell tertentu tetapi deskripsi pekerjaan untuk unix sa. lagi pertanyaannya adalah ...

Apa yang 'set -e' lakukan, dan mengapa itu dianggap berbahaya?


141
2018-05-19 16:39




Berikut ini untaian terkait: stackoverflow.com/questions/64786/error-handling-in-bash/… - Stefan Lasiewski


Jawaban:


set -e menyebabkan shell untuk keluar jika ada perintah atau pipeline mengembalikan status bukan nol.

Jawaban yang mungkin dicari pewawancara adalah:

Akan berbahaya untuk menggunakan "set -e" saat membuat skrip init.d:

Dari http://www.debian.org/doc/debian-policy/ch-opersys.html 9.3.2 -

Hati-hati menggunakan set -e di skrip init.d. Menulis skrip init.d yang benar memerlukan penerimaan berbagai status kesalahan ketika dasmon sudah berjalan atau sudah berhenti tanpa membatalkan skrip init.d, dan pustaka fungsi init.d umum tidak aman untuk dipanggil dengan set -e yang berlaku. Untuk skrip init.d, seringkali lebih mudah untuk tidak menggunakan set -e dan sebagai gantinya memeriksa hasil dari setiap perintah secara terpisah.

Ini adalah pertanyaan yang valid dari sudut pandang pewawancara karena itu memberi tahu seorang kandidat yang memiliki pengetahuan tentang scripting dan otomatisasi tingkat server


146
2017-08-09 21:01



nice find. Terima kasih. - egorgry
poin bagus. itu akan menghentikan proses boot atas sesuatu yang mungkin merupakan kesalahan teknis, tetapi seharusnya tidak menyebabkan seluruh skrip berhenti - Matt
Meskipun saya setuju dengan stackoverflow.com/questions/78497/…Saya pikir gaya ini cocok dengan bash untuk pemeriksaan init pendek dan penebangan atau patch lingkungan lainnya sebelum mengeksekusi target beban kerja. Kami menggunakan kebijakan yang sama untuk skrip init docker gambar kami. - joshperry


Dari bash(1):

          -e      Exit immediately if a pipeline (which may consist  of  a
                  single  simple command),  a subshell command enclosed in
                  parentheses, or one of the commands executed as part  of
                  a  command  list  enclosed  by braces (see SHELL GRAMMAR
                  above) exits with a non-zero status.  The shell does not
                  exit  if  the  command that fails is part of the command
                  list immediately following a  while  or  until  keyword,
                  part  of  the  test  following  the  if or elif reserved
                  words, part of any command executed in a && or  ││  list
                  except  the  command  following  the final && or ││, any
                  command in a pipeline but the last, or if the  command’s
                  return  value  is being inverted with !.  A trap on ERR,
                  if set, is executed before the shell exits.  This option
                  applies to the shell environment and each subshell envi-
                  ronment separately (see  COMMAND  EXECUTION  ENVIRONMENT
                  above), and may cause subshells to exit before executing
                  all the commands in the subshell.

Sayangnya saya tidak cukup kreatif untuk memikirkan mengapa itu akan berbahaya, selain "sisa skrip tidak akan dieksekusi" atau "mungkin mungkin menutupi masalah nyata".


33
2018-05-19 16:43



topeng masalah nyata / lainnya, ya, saya kira saya bisa melihat itu ... saya berjuang untuk datang dengan contoh itu menjadi berbahaya, juga ... - cpbills
Ada manualnya set! Saya selalu berakhir di builtin(1). Terima kasih. - Jared Beck
bagaimana saya tahu bahwa dokumentasi untuk set adalah untuk ditemukan di man 1 bash?? dan bagaimana orang bisa menemukan -e opsi untuk set kata kunci di halaman manual yang sangat besar? Anda tidak bisa /-e Cari di sini - Blauhirn
@Blauhirn menggunakan help set - Blauhirn


Perlu dicatat itu set -e dapat diaktifkan dan dinonaktifkan untuk berbagai bagian skrip. Tidak harus ada untuk seluruh eksekusi skrip. Bahkan bisa diaktifkan secara kondisional. Yang mengatakan, saya tidak pernah menggunakannya karena saya melakukan penanganan kesalahan saya sendiri (atau tidak).

some code
set -e     # same as set -o errexit
more code  # exit on non-zero status
set +e     # same as set +o errexit
more code  # no exit on non-zero status

Yang juga patut dicatat adalah ini dari bagian halaman manual Bash pada trap perintah yang juga menjelaskan caranya set -e fungsi dalam keadaan tertentu.

Itu                 Perangkap ERR tidak dijalankan jika perintah yang gagal adalah bagian dari                 daftar perintah segera setelah beberapa saat atau sampai kata kunci,                 bagian dari tes dalam pernyataan if, bagian dari perintah yang dieksekusi                 dalam daftar && atau ⎪⎪, atau jika nilai kembalian perintah sedang                 terbalik via!. Ini adalah kondisi yang sama yang dipatuhi oleh                 pilihan errexit.

Jadi ada beberapa kondisi di mana status bukan nol tidak akan menyebabkan keluar.

Saya pikir bahayanya adalah tidak mengerti kapan set -e datang ke dalam bermain dan ketika itu tidak dan mengandalkannya secara tidak benar di bawah beberapa asumsi yang tidak valid.

Silakan lihat juga BashFAQ / 105 Mengapa tidak menetapkan -e (atau mengatur -o errexit, atau menjebak ERR) melakukan apa yang saya harapkan?


19
2018-05-19 22:39



Meskipun menyimpang dari pertanyaan sedikit, jawaban ini persis seperti yang saya cari: mematikannya hanya untuk sebagian kecil dari sebuah naskah! - Stephan Bijzitter


Perlu diingat ini adalah kuis untuk wawancara kerja. Pertanyaan-pertanyaan itu mungkin telah ditulis oleh staf saat ini, dan mereka mungkin salah. Hal ini tidak selalu buruk, dan semua orang membuat kesalahan, dan pertanyaan wawancara sering duduk di sudut gelap tanpa ulasan, dan hanya keluar saat wawancara.

Sangat mungkin bahwa 'set -e' tidak melakukan apa pun yang kita anggap "berbahaya". Tetapi penulis pertanyaan itu mungkin keliru percaya bahwa 'set -e' berbahaya, karena ketidaktahuan atau bias mereka sendiri. Mungkin mereka menulis skrip shell buggy, itu membom secara mengerikan, dan mereka keliru mengira bahwa 'set -e' harus disalahkan, padahal sebenarnya mereka lalai menulis pemeriksaan kesalahan yang tepat.

Saya telah berpartisipasi dalam 40 wawancara kerja selama 2 tahun terakhir, dan para pewawancara terkadang mengajukan pertanyaan yang salah, atau memiliki jawaban yang salah.

Atau mungkin itu pertanyaan jebakan, yang akan menjadi timpang, tetapi tidak sepenuhnya tak terduga.

Atau mungkin ini penjelasan yang bagus: http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg473314.html


13
2018-05-19 17:03



+1 saya berada di perahu yang sama, dan banyak wawancara 'teknis' yang pernah saya tangani setidaknya sedikit menyesatkan. - cpbills
Wow. Temuan yang bagus di daftar debian. +1 untuk ketidaktahuan pertanyaan wawancara. Saya ingat pernah berdebat jawaban netback sejak saya 100% yakin saya benar. Mereka berkata tidak. Saya pulang ke rumah dan melakukan googling, saya benar. - egorgry


set -e beri tahu bash, dalam skrip, untuk keluar setiap kali ada yang mengembalikan nilai balik bukan nol.

Aku bisa melihat bagaimana itu akan menjengkelkan, dan buggy, tidak yakin tentang berbahaya, kecuali kamu telah membuka izin pada sesuatu, dan sebelum kamu bisa membatasi mereka lagi, skripmu mati.


9
2018-05-19 16:46



Itu menarik. Saya tidak berpikir tentang izin yang dibuka dalam skrip yang mati sebelum waktunya tetapi saya dapat melihat bahwa dianggap berbahaya. Bagian yang menyenangkan dari kuis ini adalah bahwa Anda tidak dapat menggunakan bahan referensi seperti pria atau google dan jika Anda tidak dapat menjawab sepenuhnya, jangan menjawabnya sama sekali. - egorgry
itu hanya konyol, saya akan mempertimbangkan kembali perusahaan ini ... bercanda (semacam). bagus untuk memiliki basis pengetahuan yang kuat, tetapi setengah dari kerja TI adalah mengetahui / di mana / menemukan informasi ... semoga mereka cukup pintar untuk mempertimbangkannya ketika mencetak pelamar. di samping catatan, saya melihat / tidak / digunakan untuk set -e, pada kenyataannya, bagi saya itu berbicara tentang kemalasan untuk mengabaikan pengecekan kesalahan dalam skrip Anda ... jadi ingatlah itu, dengan majikan ini, juga ... jika mereka menggunakannya banyak, seperti apa skrip mereka, bahwa Anda mau tidak mau harus mempertahankan ... - cpbills
titik sempurna @cpbills. Saya juga melihat tidak ada gunanya untuk mengatur -e dalam skrip dan mungkin mengapa itu membuat saya sangat bingung. Saya ingin memposting semua pertanyaan karena beberapa benar-benar baik dan beberapa benar-benar aneh dan acak seperti ini. - egorgry
Saya telah melihatnya di banyak sistem cron jobs ... - Andrew


set -e mengakhiri skrip jika kode keluar non-nol ditemui, kecuali dalam kondisi tertentu. Untuk merangkum bahayanya penggunaannya dalam beberapa kata: ia tidak berperilaku seperti yang orang kira.

Menurut pendapat saya, itu harus dianggap sebagai hack berbahaya yang terus ada untuk keperluan kompatibilitas saja. Itu set -e Pernyataan tidak mengubah shell dari bahasa yang menggunakan kode kesalahan ke dalam bahasa yang menggunakan aliran kontrol seperti pengecualian, itu hanya upaya buruk untuk meniru perilaku itu.

Greg Wooledge telah banyak berbicara tentang bahayanya set -e:

Di tautan kedua, ada berbagai contoh perilaku tidak disengaja dan tidak dapat diprediksi set -e.

Beberapa contoh perilaku tidak intuitif set -e (beberapa diambil dari tautan wiki di atas):

  • mengatur -e
    x = 0
    biarkan x ++
    echo "x adalah $ x"
    Di atas akan menyebabkan skrip shell keluar sebelum waktunya, karena let x++ mengembalikan 0, yang diperlakukan oleh let kata kunci sebagai nilai falsy dan berubah menjadi kode keluar non-nol. set -e pemberitahuan ini, dan diam-diam mengakhiri skrip.
  • mengatur -e
    [-d / opt / foo] && echo "Peringatan: foo sudah terpasang. Akan ditimpa." > & 2
    echo "Memasang foo ..."
    

    Cara di atas berfungsi sesuai harapan, mencetak peringatan jika /opt/foo sudah ada.

    mengatur -e
    check_previous_install () {
        [-d / opt / foo] && echo "Peringatan: foo sudah terpasang. Akan ditimpa." > & 2
    }
    
    check_previous_install
    echo "Memasang foo ..."
    

    Di atas, meskipun satu-satunya perbedaan adalah bahwa satu baris telah direfungsi ke fungsi, akan berakhir jika /opt/foo tidak ada. Ini karena fakta bahwa itu bekerja awalnya adalah pengecualian khusus untuk set -eperilaku. Kapan a && b mengembalikan bukan nol, itu diabaikan oleh set -e. Namun, sekarang karena fungsinya, kode keluar dari fungsi sama dengan kode keluar dari perintah itu, dan fungsi yang kembali bukan nol akan secara diam-diam mengakhiri skrip.

  • mengatur -e
    IFS = $ '\ n' baca -d '' -r -a config_vars <config
    

    Di atas akan membaca larik config_vars dari file config. Sebagai penulis mungkin berniat, itu berakhir dengan kesalahan jika config hilang. Karena penulis mungkin tidak berniat, itu diam-diam berakhir jika config tidak berakhir di baris baru. Jika set -e tidak digunakan di sini, lalu config_vars akan berisi semua baris file apakah atau tidak itu berakhir di baris baru.

    Pengguna Teks Sublime (dan editor teks lainnya yang menangani baris baru salah), berhati-hatilah.

  • mengatur -e
    
    should_audit_user () {
        grup grup lokal = "$ (grup" $ 1 ")"
        untuk grup dalam $ grup; melakukan
            jika ["$ group" = audit]; kemudian kembali 0; fi
        selesai
        kembali 1
    }
    
    jika should_audit_user "$ user"; kemudian
        logger 'Blah'
    fi
    

    Penulis di sini mungkin berharap bahwa jika untuk beberapa alasan pengguna $user tidak ada, maka groups perintah akan gagal dan skrip akan berakhir alih-alih membiarkan pengguna melakukan beberapa tugas yang tidak diaudit. Namun, dalam hal ini set -e penghentian tidak akan berpengaruh. Jika $user tidak dapat ditemukan untuk beberapa alasan, daripada mengakhiri skrip, should_audit_user fungsi hanya akan mengembalikan data yang salah seakan-akan set -e tidak berlaku.

    Ini berlaku untuk fungsi apa pun yang dipanggil dari bagian kondisi a if pernyataan, tidak peduli seberapa dalam bersarang, di mana pun itu didefinisikan, tidak peduli bahkan jika Anda berlari set -e di dalamnya lagi. Menggunakan if pada setiap titik sepenuhnya menonaktifkan efek set -e sampai blok kondisi sepenuhnya dijalankan. Jika penulis tidak menyadari jebakan ini, atau tidak tahu seluruh panggilan mereka menumpuk dalam semua situasi yang memungkinkan di mana suatu fungsi dapat dipanggil, maka mereka akan menulis kode kereta dan rasa aman palsu yang disediakan oleh set -e setidaknya akan disalahkan sebagian.

    Bahkan jika penulis sepenuhnya sadar akan jebakan ini, solusinya adalah menulis kode dengan cara yang sama seperti orang akan menulisnya tanpa set -e, secara efektif rendering yang beralih kurang dari tidak berguna; tidak hanya penulis harus menulis kode penanganan kesalahan manual seolah-olah set -e tidak berpengaruh, tetapi kehadiran set -e mungkin membodohi mereka dengan berpikir bahwa mereka tidak perlu melakukannya.

Beberapa kelemahan lebih lanjut dari set -e:

  • Ini mendorong kode yang berantakan. Penangan kesalahan benar-benar dilupakan, dengan harapan bahwa apa pun yang gagal akan melaporkan kesalahan dengan cara yang masuk akal. Namun, dengan contoh-contoh seperti let x++ di atas, bukan ini masalahnya. Jika skrip tiba-tiba mati, biasanya secara diam-diam, yang menghambat debug. Jika skrip tidak mati dan Anda mengharapkannya (lihat butir peluru sebelumnya), maka Anda memiliki bug yang lebih halus dan berbahaya di tangan Anda.
  • Ini membawa orang ke rasa aman yang salah. Lihat lagi iftitik peluru -kondisi.
  • Tempat-tempat di mana shell berakhir tidak konsisten antara shell atau versi shell. Dimungkinkan untuk secara tidak sengaja menulis skrip yang berperilaku berbeda pada versi bash yang lebih lama karena perilaku set -e telah tweak antara versi tersebut.

set -e adalah masalah yang kontroversial, dan beberapa orang yang sadar akan masalah yang ada di sekitarnya menyarankan untuk tidak melakukannya, sementara beberapa yang lain hanya menyarankan untuk berhati-hati saat aktif untuk mengetahui jebakan. Ada banyak shell scripting newbies yang merekomendasikan set -epada semua skrip sebagai tangkapan-semua untuk kondisi kesalahan, tetapi dalam kehidupan nyata tidak berfungsi seperti itu.

set -e tidak ada pengganti untuk pendidikan.


5
2018-04-27 23:06





Saya akan mengatakan itu berbahaya karena Anda tidak mengontrol aliran naskah Anda lagi. Skrip dapat berakhir selama ada perintah yang diminta oleh skrip mengembalikan bukan nol. Jadi yang harus Anda lakukan adalah melakukan sesuatu yang mengubah perilaku atau keluaran dari salah satu komponen, dan Anda harus mengakhiri skrip utama. Mungkin lebih dari masalah gaya, tetapi pasti memiliki konsekuensi. Bagaimana jika naskah utama Anda itu seharusnya memasang bendera, dan itu bukan karena diakhiri lebih awal? Anda akhirnya akan merusak seluruh sistem jika menganggap bendera harus ada di sana, atau bekerja dengan nilai default atau lama yang tidak diharapkan.


2
2018-05-19 18:07



Setuju dengan jawaban ini. Ini bukan secara inheren berbahaya, tetapi ini adalah kesempatan untuk keluar awal yang tidak terduga. - pboin
Apa yang saya ingatkan ini adalah profi C ++ milik saya yang selalu menarik poin dari tugas saya karena tidak memiliki titik masuk tunggal / titik keluar tunggal dalam sebuah program. Saya pikir itu murni hal 'prinsip', tetapi bisnis set -e ini pasti mendemonstrasikan bagaimana dan mengapa semuanya bisa benar-benar lepas kendali. Program akhirnya adalah tentang kontrol dan determinisme, dan dengan penghentian prematur Anda menyerah keduanya. - Marcin


Sebagai contoh yang lebih konkrit dari jawaban @ Marcin yang telah secara pribadi menggigit saya, bayangkan ada a rm foo/bar.txt baris di suatu tempat di naskah Anda. Biasanya bukan masalah besar jika foo/bar.txt sebenarnya tidak ada. Namun dengan set -e hadir sekarang naskah Anda akan berakhir lebih awal di sana! Ups.


0
2018-06-22 19:00