Soru 'Set -e' ne yapar ve neden tehlikeli olarak değerlendirilebilir?


Bu soru ön görüşme sınavında ortaya çıktı ve bu beni çıldırtıyor. Bunu herkes cevaplayabilir ve rahatlatır mı? Sınavın belirli bir kabuğa referansı yoktur, ancak iş tanımı unix sa içindir. yine soru basitçe ...

'Set -e' ne yapar ve neden tehlikeli olarak değerlendirilebilir?


142
2018-05-19 16:39


Menşei


İşte ilgili bir konu: stackoverflow.com/questions/64786/error-handling-in-bash/... - Stefan Lasiewski


Cevaplar:


set -e Herhangi bir alt komut veya boru hattı sıfır olmayan bir durum döndürürse kabuğun çıkmasına neden olur.

Görüşmecinin aradığı cevap şu:

İnit.d komut dosyaları oluşturulurken "set -e" kullanmak tehlikeli olabilir:

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

İnit.d komutlarında set -e'yi kullanmamaya dikkat edin. Doğru init.d betiklerinin yazılması, init.d komut dosyasını iptal etmeden zaten çalışmakta olan veya zaten durdurulduğunda, çeşitli hata çıkış durumlarını kabul etmeyi gerektirir ve ortak init.d işlev kitaplıkları, set -e etkin olarak çağırmak için güvenli değildir. İnit.d betikleri için, set -e'yi kullanmamak genellikle daha kolaydır ve bunun yerine her bir komutun sonucunu ayrı ayrı kontrol edin.

Bu bir görüşmeci açısından geçerli bir sorudur, çünkü sunucu düzeyinde komut dosyası oluşturma ve otomasyon konusunda çalışan bir adayı değerlendirir.


148
2017-08-09 21:01



güzel bul. Teşekkürler. - egorgry
iyi bir nokta. önyükleme işlemini teknik olarak bir hata olabilecek bir şey üzerinde durduracak, ancak tüm komut dosyasının durmasına neden olmamalıdır. - Matt
Ben katılıyorum rağmen stackoverflow.com/questions/78497/...Bence bu tarz, hedef iş yükünü çalıştırmadan önce kısa init kontrolleri ve günlüğe kaydetme veya başka bir ortam yaması için bash ile iyi bir uyum bulur. Bu aynı politikayı docker imge init betikleri için kullanıyoruz. - joshperry


itibaren 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.

Ne yazık ki, "senaryonun geri kalanı idam edilmeyecek" veya "belki de gerçek sorunları maskeleyebilir" dışında neden tehlikeli olabileceğini düşünecek kadar yaratıcı değilim.


33
2018-05-19 16:43



Maske gerçek / diğer problemler, evet, sanırım bunu görebiliyordum ... Tehlikeli bir örnek bulmaya çalışıyordum ... - cpbills
Manpage var set! Ben her zaman builtin(1). Teşekkürler. - Jared Beck
belgelerin nasıl olduğunu bilirdim set içinde olmak man 1 bash?? ve kimsenin nasıl bulacağını -e için seçenek set manuel sayfada anahtar kelime çok mu büyük? sadece yapamazsın /-e burada ara - Blauhirn
@Blauhirn kullanarak help set - Blauhirn


bu not alınmalı set -e Bir komut dosyasının çeşitli bölümleri için açılıp kapatılabilir. Tüm senaryonun icrası için açık olmak zorunda değil. Şartlı olarak bile etkinleştirilebilir. Yani, kendi hata işlemimi yaptığımdan (veya yapmadığımdan) hiç kullanmadım.

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

Ayrıca Bash man sayfa bölümünden dikkat çekicidir. trap nasıl da açıklayan komut set -e belirli koşullar altında çalışır.

                Hatalı komutun bir parçası ise ERR tuzağı yürütülmez.                 bir süre sonra veya anahtar kelime kadar hemen komut listesi                 Bir if ifadesinde testin parçası, çalıştırılan bir komutun parçası                 && veya ⎪⎪ listesinde veya komutun dönüş değeri devam ediyorsa                 üzerinden tersine çevrildi! Bunlar aynı şartlara uyuyor                 errexit seçeneği.

Yani sıfır olmayan bir durumun çıkışa neden olmayacağı bazı koşullar vardır.

Tehlikenin ne zaman anlaşıldığını düşünüyorum set -e oyuna girer ve geçersiz bir varsayımın altında yanlış bir şekilde bulunmadığı ve buna güvenmediği zaman gelir.

Lütfen de görmek BashFAQ / 105 Neden -e (veya -o errexit veya trap ERR) beklediğim şeyi yapmıyor?


19
2018-05-19 22:39



Sorudan biraz saparken, bu cevap tam olarak aradığım şey: bir senaryonun sadece küçük bir kısmı için onu kapatmak! - Stephan Bijzitter


Bu bir iş görüşmesi için bir sınav olduğunu unutmayın. Sorular mevcut personel tarafından yazılmış olabilir ve yanlış olabilirler. Bu mutlaka kötü değildir ve herkes hata yapar ve röportaj soruları genellikle gözden geçirilmeden karanlık bir köşede oturur ve sadece bir röportaj sırasında ortaya çıkar.

'Set -e' nin 'tehlikeli' olarak kabul edeceğimiz hiçbir şey yapmadığı tamamen mümkündür. Ancak bu soruyu yazan yazar yanlışlıkla 'ce -e' nin kendi cehaleti veya yanlılığı nedeniyle tehlikeli olduğuna inanabilir. Belki de buggy bir kabuk mektubu yazdılar, korkunç bir şekilde bombaladılar ve yanlışlıkla yanlış bir hata kontrolü yazmayı ihmal ettikleri için 'set -e' 'nin sorumlu olduğunu düşündüler.

Muhtemelen son 2 yılda 40 iş görüşmesine katıldım ve görüşmeciler bazen yanlış olan ya da yanlış olan soruları soruyorlar.

Ya da topal olabilecek, ama tamamen beklenmedik bir hile sorusu olabilir.

Ya da belki bu iyi bir açıklamadır: http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg473314.html


13
2018-05-19 17:03



+1 Aynı teknedeyim ve uğraştığım birçok 'teknik' görüşme en azından biraz yanlış yönlendirildi. - cpbills
vay. Debian listesinde iyi bul. Görüşme sorularının cehaleti için +1. Doğru olduğumdan% 100 emin olduğumdan beri bir netback cevabını tartıştığımı hatırlıyorum. Hayır dediler. Eve gittim ve googled ettim, haklıymışım. - egorgry


set -e Bir betikte bash'a, hiçbir şeyin sıfır olmayan bir dönüş değeri döndürdüğü zaman çıkmasını söyler.

Bir şey üzerinde izinler açmış olmadıkça ve onları tekrar kısıtlayabilmeden önce, can sıkıcı ve buggy'nin tehlikeli olduğundan emin olamayacağını görebiliyordum, senaryonuz öldü.


9
2018-05-19 16:46



İlginç. Önceden ölen bir senaryoda açılan izinleri düşünmedim ama tehlikeli sayıldığını görebiliyordum. Bu testin eğlenceli kısmı, erkek ya da google gibi referans materyalleri kullanamayacağınız ve yanıtlayamazsanız tamamen yanıtlamamanızdır. - egorgry
Bu sadece aptalca, bu işvereni tekrar düşünürdüm ... şaka yapıyorum. Güçlü bir bilgi tabanına sahip olmak iyidir, ancak BT çalışmasının yarısı bilgiyi / nerede / nerede bulacağını bilmekte ... umarız ki, başvuru sahiplerini puanlarken bunu dikkate alacak kadar akıllılardı. bir yan notta, ben / hayır / için kullanın set -eAslında bana göre, komut dosyalarınızda hata kontrolünü görmezden gelmek için tembellikten bahsediyor ... işte bu işverenle de unutmayın, eğer çok kullanıyorlarsa, senaryoları neye benziyorsa, kaçınılmaz olarak sürdürmek zorunda kalacak ... - cpbills
Mükemmel nokta @cbbills. Ayrıca bir senaryoda set -e için hiçbir kullanım görmüyorum ve muhtemelen bu yüzden beni çok şaşırttı. Bazı sorular gerçekten iyi olduğu için bazı soruları göndermek istiyorum ve bazıları bu gibi gerçekten tuhaf ve rastgele. - egorgry
Birçok sistem cron işinde gördüm. - Andrew


set -e Belirli koşullar dışında, sıfır olmayan bir çıkış koduyla karşılaşıldığında komut dosyasını sonlandırır. Kullanımının tehlikelerini birkaç kelimeyle özetlemek gerekirse: İnsanların bunu nasıl yaptığını düşünmez.

Benim düşünceme göre, sadece uyumluluk amacıyla var olmaya devam eden tehlikeli bir hack olarak görülmelidir. set -e deyimi, kabukları istisna benzeri bir denetim akışı kullanan bir dile hata kodları kullanan bir dilden döndürmez; yalnızca bu davranışı taklit etmeye çalışır.

Greg Wooledge'nin tehlikeleri hakkında söylenecek çok şey var set -e:

İkinci bağlantıda, beklenmedik ve tahmin edilemez davranışların çeşitli örnekleri vardır. set -e.

Kasti olmayan davranışının bazı örnekleri set -e (bazıları yukarıdaki wiki bağlantısından alınmıştır):

  • set -e
    x = 0 olduğu
    x ++ yapalım
    echo "x, $ x" dir
    Yukarıdaki, kabuk betiğinin erken çıkmasına neden olacaktır, çünkü let x++ tarafından döndürülen 0 değerini döndürür let false değeri olarak anahtar kelime ve sıfır olmayan bir çıkış koduna dönüştürüldü. set -e bunu fark eder ve komut dosyasını sessizce sonlandırır.
  • set -e
    [-d / opt / foo] && echo "Uyarı: foo zaten yüklü. Üzerine yazılacak." > Ve 2
    echo "Yüklüyor ..."
    

    Yukarıdaki gibi beklendiği gibi çalışıyorsa, bir uyarı yazdırıyorsanız /opt/foo zaten var.

    set -e
    check_previous_install () {
        [-d / opt / foo] && echo "Uyarı: foo zaten yüklü. Üzerine yazılacak." > Ve 2
    }
    
    check_previous_install
    echo "Yüklüyor ..."
    

    Yukarıdaki tek fark, tek bir satırın bir fonksiyona dönüştürülmesidir. /opt/foo mevcut değil. Bunun nedeni, orijinal olarak çalıştığı gerçeğinin özel bir istisna olmasıdır. set -edavranışı. Ne zaman a && b sıfırdan döndürür, tarafından yok sayılır set -e. Ancak, şimdi bir işlev, işlevin çıkış kodu, bu komutun çıkış koduna eşittir ve sıfırdan dönen işlev, komut dosyasını sessizce sonlandırır.

  • set -e
    IFS = $ '\ n' read -d '' -r -a config_vars <config
    

    Yukarıdaki dizi okuyacaktır config_vars dosyadan config. Yazar niyetinde olabileceği gibi, eğer bir hata ile son bulursa config kayıp. Yazar niyetinde olmayabilir, eğer sessizce sona erer config bir satırsonu ile bitmez. Eğer set -e burada kullanılmadı, o zaman config_vars bir satırsonu içinde bitip bitmediğine bakılmaksızın dosyanın tüm satırlarını içerecektir.

    Sublime Text kullanıcıları (ve yeni satırları yanlış kullanan diğer metin editörleri), dikkat et.

  • set -e
    
    should_audit_user () {
        yerel grup grupları = "$ (gruplar" 1 $ ")"
        $ grupları içindeki grup için; yap
            ["$ group" = audit]; daha sonra 0; fi
        tamam
        geri dönüş 1
    }
    
    eğer should_audit_user "$ kullanıcı"; sonra
        logger 'Blah'
    fi
    

    Buradaki yazar, bir sebepten ötürü makul bir şekilde bekleyebilir. $user yok, o zaman groups komut başarısız olur ve kullanıcı, bazı görevi denetlenmeyen bir görev gerçekleştirmek yerine komut dizisi sona erer. Ancak, bu durumda set -e fesih hiçbir zaman yürürlüğe girmez. Eğer $user komut dosyasının sonlandırılması yerine, herhangi bir nedenle bulunamadı should_audit_user işlev yanlış verileri yalnızca set -e yürürlükte değildi.

    Bu, durumun bir bölümünden çağrılan herhangi bir işlev için geçerlidir. if deyim, ne kadar derinlemesine iç içe olursa olsun, nerede tanımlanırsa yapılsın, kaçarsanız bile set -e tekrar içinde. kullanma if herhangi bir noktada tamamen etkisiz hale getirir set -e Durum bloğu tamamen yürütülene kadar. Eğer yazar bu tuzaktan haberdar değilse veya bir fonksiyonun çağrılabileceği tüm olası durumlarda çağrı yığınının tamamını bilmiyorsa, o zaman onlarca kodu ve yanlış güvenlik duygusunu yazacaktır. set -e En azından kısmen suçlanacak.

    Yazar, bu tuzaktan tamamen haberdar olsa bile, geçici çözüm, kod yazmadan yazılanla aynı şekilde yazmaktır. set -eBu anahtarın işe yaramazdan daha az etkili bir şekilde işlenmesi; yazar sadece manuel hata işlem kodu yazmak zorunda değil set -e yürürlükte değildi, ama varlığı set -e zorunda olmadıklarını düşünerek onları aldatmış olabilirler.

Başka bazı dezavantajları set -e:

  • Özensiz kodu teşvik eder. Hata işleyicileri, hatayı ne zaman başarısız olursa olsun, bazı mantıklı bir şekilde rapor edecekleri umuduyla tamamen unutulur. Ancak, örneklerle let x++ yukarıda, bu durum böyle değil. Komut dosyası beklenmedik şekilde ölürse, genellikle sessizdir ve bu da hata ayıklamayı engeller. Eğer betik ölmüyorsa ve onu beklemektesiniz (önceki mermi noktasına bakınız), elinizde daha ince ve sinsi bir böcek var.
  • İnsanları yanlış bir güvenlik hissine yönlendirir. Tekrar bakın if-Kısım mermi noktası.
  • Kabuğun sonlandığı yerler kabuklar veya kabuk versiyonları arasında tutarlı değildir. Yanlışlıkla, bash'ın eski bir sürümünde farklı davranışlar sergileyen bir betik yazması set -e Bu sürümler arasında değiştirildi.

set -e tartışmalı bir konudur ve çevreleyen konuların farkında olan bazı insanlar buna karşı tavsiyede bulunurken, bazıları ise tuzakları bilmek için aktifken dikkatli olmalarını tavsiye etmektedir. Orada tavsiye birçok kabuk betik yeniler var set -eTüm betiklerde hata koşullarını yakalamak için kullanılır, ancak gerçek hayatta bu şekilde çalışmaz.

set -e eğitimin yerini tutamaz.


6
2018-04-27 23:06





Tehlikeli olduğunu söyleyebilirim çünkü sen artık senaryonun akışını kontrol etmiyorsun. Komut dosyası, komut dosyasının başlattığı komutlardan herhangi biri sıfırdan farklı bir süre sonra sona erebilir. Yapmanız gereken tek şey, bileşenlerin herhangi birinin davranışını veya çıktısını değiştiren bir şey yapmak ve ana senaryoyu sonlandırmaktır. Daha çok bir stil problemi olabilir, ama kesinlikle sonuçları vardır. Ya senin ana senaryonun bir bayrak koyması gerekiyorsa ve erken bitmesi yüzünden yapmazsa? Bayrağın orada olması ya da beklenmedik bir varsayılan ya da eski bir değerle çalışmasının varlığını varsayarsa, sistemin geri kalanında bir hata yaparsınız.


2
2018-05-19 18:07



Bu cevaba tamamen katılıyorum. Değil doğal olarak Tehlikeli, ama beklenmedik bir erken çıkışa sahip olmak için bir fırsat. - pboin
Bunun bana hatırlattığı şey, bir programda tek giriş noktası / tek çıkış noktası olmaması nedeniyle ödevlerimden her zaman puan alan bir C ++ prof. Tamamen 'ilke' bir şey olduğunu düşünmüştüm, ama bu set -e iş, şeylerin neden ve nasıl kontrol edilebildiğini kesinlikle ortaya koyar. Nihayetinde programlar kontrol ve determinizm ile ilgilidir ve erken sona erdirme ile her ikisinden de vazgeçersiniz. - Marcin


Bana şahsen beni ısırdı @ Marcin'in cevabı daha somut bir örnek olarak, bir hayal olduğunu rm foo/bar.txt senaryonun içinde bir yer. Genellikle eğer büyük bir anlaşma foo/bar.txt aslında mevcut değil. Bununla birlikte set -e şimdi mevcut betiğiniz orada erken sona erecek! Hata.


0
2018-06-22 19:00