'Set-e' ne yapar ve neden tehlikeli olarak kabul edilebilir?


147

Bu soru görüşme öncesi bir sınavda ortaya çıktı ve beni çıldırtıyor. Birisi bunu cevaplayıp beni rahatlatabilir mi? Testin belirli bir kabuk için referansı yoktur, ancak iş tanımı unix sa içindir. tekrar soru basitçe ...

'Set-e' ne yapar ve neden tehlikeli olarak kabul edilebilir?


Yanıtlar:


154

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

Görüşme yapan kişinin aradığı cevap muhtemelen:

İnit.d scriptleri oluştururken "set -e" kullanmak tehlikeli olabilir:

Gönderen http://www.debian.org/doc/debian-policy/ch-opersys.html 9.3.2 -

Set -e komutunu init.d komut dosyalarında kullanmaya dikkat edin. Doğru init.d komut dosyalarının yazılması, ödemeler zaten çalışırken veya zaten init.d komut dosyasını iptal etmeden durduğunda çeşitli hata çıkış durumlarını kabul etmeyi gerektirir ve genel init.d işlev kitaplıklarının set -e işlevinin etkin olmasıyla aranması güvenli değildir. İnit.d scriptleri için set -e kullanmamak ve her komutun sonucunu ayrı ayrı kontrol etmek genellikle daha kolaydır.

Bu, görüşmeci açısından geçerli bir sorudur, çünkü aday düzeyinde sunucu düzeyinde komut dosyası çalıştırma ve otomasyon bilgisini ölçmektedir.


iyi bir nokta. teknik olarak hata olabilecek bir şey yüzünden önyükleme işlemini durduracaktır, ancak tüm komut dosyasının durmasına neden olmamalıdır
Matt

Bununla birlikte stackoverflow.com/questions/78497/… ile aynı fikirdeyim , sanırım bu tarz kısa init kontrolleri ve kütük kaydı ya da hedef çevre iş yükünü uygulamadan önce diğer çevre maymunu yamaları için bash ile iyi bir uyum buluyor. init komut dosyaları.
joshperry

33

Kimden 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, "betiğin geri kalanı idam edilmeyecek" veya "belki de gerçek problemleri maskeleyebilir" dışında neden tehlikeli olacağını düşünecek kadar yaratıcı değilim.


1
gerçek / diğer problemleri maskelemek, evet, sanırım görebiliyordum ... tehlikeli olduğunu da
düşünmekle uğraşıyordum

Manpage için var set! Ben her zaman sonunda olurum builtin(1). Teşekkürler.
Jared Beck

nasıl belgeleri bilemez setiçinde befound etmektir man 1 bash?? ve anahtar kelime -eiçin bu seçeneği setçok büyük olan manuel bir sayfada nasıl bulabileceksiniz ? sadece /-eburada arama yapamam
phil294 5:17

@Blauhirn kullanarakhelp set
phil294

19

set -eBir betiğin çeşitli bölümleri için açılıp kapatılabileceği belirtilmelidir . Komut dosyasının yürütülmesi için açık olması gerekmez. Koşullu olarak bile etkinleştirilebilir. Bununla birlikte, kendi hata işlemeyi yaptığımdan (ya da yapmadığımdan beri) hiç kullanmıyorum.

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 dikkat edilmesi gereken, trapkomutun set -ebelirli koşullar altında nasıl işlediğini de açıklayan Bash man sayfa bölümündendir .

Başarısız olan komut bir süre sonra veya anahtar kelimeye kadar hemen sonra komut listesinin bir parçasıysa, bir if ifadesinde testin bir parçası, & & veya ⎪⎪ listesinde yürütülen bir komutun parçasıysa veya komutun komutunda ERR kapanı çalıştırılmaz. dönüş değeri! Bunlar errexit seçeneğinin uyduğu şartlar.

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

Tehlikenin ne set -ezaman devreye girdiğini ve ne zaman ortaya çıkmadığını ve bazı yanlış varsayımlar altında yanlış şekilde dayandığını anlamadığını düşünüyorum .

Lütfen ayrıca bkz. BashFAQ / 105 Neden -e (veya set -o errexit, veya ERR tuzağı) beklediğim şeyi yapmıyor?


Sorudan biraz sapmakla birlikte, bu cevap tam olarak aradığım şey: bir betiğin sadece küçük bir kısmı için kapatmak!
Stephan Bijzitter

13

Bunun bir iş görüşmesi için bir sınav olduğunu unutmayın. Sorular mevcut personel tarafından yazılmış olabilir ve yanlış olabilir. Bu mutlaka fena değil ve herkes hata yapar ve görüşme soruları genellikle gözden geçirilmeden karanlık bir köşeye oturur ve yalnızca görüşme sırasında ortaya çıkar.

'Set -e'nin' tehlikeli 'olduğunu düşündüğümüz hiçbir şey yapmaması tamamen mümkündür. Ancak bu sorunun yazarı yanlışlıkla 'cehaletin' kendi cehaletleri veya önyargıları nedeniyle tehlikeli olduğuna inanabilir. Belki de bir kabarık kabuk senaryosu yazdılar, korkunç bir şekilde bombaladılar ve yanlışlıkla 'set-e'nin suçlu olduğunu düşündüler, aslında doğru hata kontrolü yazmayı ihmal ettiler.

Son 2 yılda 40 iş görüşmesine katıldım ve görüşmeciler bazen yanlış veya yanlış cevaplar olan sorular soruyorlar.

Ya da belki hileli bir soru, ki topal olurdu, ama tamamen beklenmedik değil.

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


1
+1 Aynı gemideyim ve uğraştığım 'teknik' görüşmelerin çoğu en azından biraz yanlış yönlendirildi.
cpbills

1
vay. Debian listesinde iyi bulmak. Görüşme sorularının cehaletinden dolayı +1. Haklı olduğumdan% 100 emin olduğumdan beri bir netback cevabı savunduğumu hatırlıyorum. Hayır dediler. Eve gittim ve googled, haklıydım.
egorgry

9

set -e bash komut dosyasında, bir şey sıfır olmayan bir dönüş değeri döndürdüğünde çıkmasını söyler.

Bir şey için izinleri açmadıysanız, tehlikeli olacağından emin değil nasıl sinir bozucu ve adamcağımı görebildim ve onları yeniden kısıtlamadan önce, senaryonuz öldü.


İlginç. Zamanından önce ölen bir senaryoda açılan izinleri düşünmedim, ancak bunun tehlikeli sayıldığını görebiliyordum. Bu sınavın eğlenceli yanı, man veya google gibi referans materyalleri kullanamamanız ve tam olarak cevaplayamıyorsanız hiç cevaplamamanızdır.
egorgry

6
Bu sadece aptalca, bu işvereni tekrar düşünürdüm ... şaka (tür). Güçlü bir bilgi tabanına sahip olmak iyidir, ancak BT çalışmasının yarısı bilgiyi / nerede / bilgiyi bulmaktır ... umarım başvuruları puanlarken bunu dikkate alacak kadar akıllıdırlar. Bir yan notta, set -easlında, bana göre, senaryolarınızdaki hata kontrolünü göz ardı etmek tembellikten bahsediyor ... bu nedenle, bu işverenle de bunu aklınızda bulundurun. çok, senaryoları neye benziyor, kaçınılmaz olarak sürdürmek zorunda
kalacaksınız

Mükemmel nokta @cpbills. Ayrıca bir betikte set -e kullanmanın bir faydası göremiyorum ve bu yüzden beni çok fazla etkiledi. Bazıları gerçekten iyi, bazıları gerçekten tuhaf ve rastgele olduğu için tüm soruları göndermek istiyorum.
egorgry

Ben birçok sistem cron işlerinde gördüm ...
Andrew

8

set -eBelirli koşullar dışında sıfır olmayan bir çıkış koduyla karşılaşılırsa betiği sonlandırır. Kullanımının tehlikelerini birkaç kelimeyle özetlemek gerekirse: İnsanların yaptıklarını düşündüğü gibi davranmaz.

Benim düşünceme göre, sadece uyumluluk amacıyla varlığını sürdüren tehlikeli bir saldırı olarak kabul edilmelidir. set -eİstisna benzeri kontrol akışını kullanan bir dile hata kodları kullanan bir dilden kabuk açılmıyor açıklamada, bu sadece kötü davranışı taklit etmeye çalışır.

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

İkinci linkte, sezgisel ve tahmin edilemez davranışların çeşitli örnekleri vardır set -e.

Sezgisel olmayan davranışlarından set -ebazıları (bazıları yukarıdaki wiki bağlantısından alınmış):

  • -e ayarla
    x = 0 olduğu
    izin x ++
    yankı "x $ x"
    Yukarıdakiler, kabuk betiğinin zamanından önce çıkmasına neden olacaktır, çünkü anahtar kelime let x++tarafından letsahte bir değer olarak kabul edilen ve sıfır olmayan bir çıkış koduna dönüştürülen 0 değerini döndürür. set -ebunu fark eder ve sessizce betiği sonlandırır.
  • -e ayarla
    [-d / opt / foo] && echo "Uyarı: foo zaten kurulu. Üzerine yazacak." > Ve 2
    echo "Yükleme ..."
    

    Yukarıdakiler beklendiği gibi çalışır, /opt/foozaten varsa bir uyarı yazdırır .

    -e ayarla
    check_previous_install () {
        [-d / opt / foo] && echo "Uyarı: foo zaten kurulu. Üzerine yazacak." > Ve 2
    }
    
    check_previous_install
    echo "Yükleme ..."
    

    Yukarıdakiler, tek bir çizginin bir işleve yeniden yansıtılmasının tek fark olmasına rağmen, /opt/foomevcut değilse sona erecektir . Bunun nedeni asıl işe yaradığı gerçeği, set -edavranışının özel bir istisnasıdır . Ne zaman a && bdöner sıfırdan farklı, o tarafından göz ardı edilir set -e. Ancak, bu bir fonksiyon olduğu için, fonksiyonun çıkış kodu o komutun çıkış koduna eşittir ve sıfır döndürmeyen fonksiyon komut dosyasını sessizce sonlandırır.

  • -e ayarla
    IFS = $ '\ n' okuma -d '' -r -a config_vars <config
    

    Yukarıdaki config_varsdosya dizisinden okuyacaktır config. Yazarın niyetinde olabileceği gibi config, eksikse bir hatayla sonlanır . Yazar niyetlenmeyebileceğinden, configyeni bir satırda bitmezse sessizce sona erer . Eğer set -eburada kullanılmadı, sonra config_varsyeni bir satırdan sona erdi olsun veya olmasın dosyanın tüm satırları içerecektir.

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

  • -e ayarla
    
    should_audit_user () {
        yerel grup grupları = "$ (" $ 1 ") gruplar"
        $ gruplar içindeki grup için; yap
            eğer ["$ group" = denetim]; sonra 0 döndürün; fi
        tamam
        1 dönüş
    }
    
    should_audit_user "$ user" ise; sonra
        logger 'Blah'
    fi
    

    Buradaki yazar, bir nedenden ötürü kullanıcının $userolmaması groupsdurumunda , komutun başarısız olacağını ve kullanıcının denetlenmeyen bir görevi yerine getirmesine izin vermek yerine komut dosyasının sonlandırılmasını bekleyebilir . Ancak, bu durumda set -efesih asla geçerli olmaz. Herhangi bir $usersebepten dolayı bulunamazsa, betiği sonlandırmak yerine, should_audit_userişlev set -eetkin değilmiş gibi yanlış verileri döndürür .

    Bu, bir ififadenin koşulu kısmından çağrılan tüm işlevler için geçerlidir; ne kadar iç içe olursa olsun, nerede tanımlanmış olursa olsun, set -etekrar içeri girseniz bile . ifHerhangi bir noktada kullanılması set -e, durum bloğu tamamen yürütülene kadar etkisini devre dışı bırakır . Eğer yazar bu engelin farkında değilse ya da bir fonksiyonun çağrılabileceği tüm olası durumlarda tüm çağrı yığınlarını bilmiyorsa, buggy kodu yazacak ve sağladığı yanlış güvenlik duygusu set -een azından kısmen suçlarlar.

    Yazar bu eksikliğin tam olarak farkında olsa bile, geçici çözüm, kodun bir yazmadan yazdığı gibi yazılması set -e, bu geçişin faydasızdan daha az etkili olması; yazarın sadece el ile yapılan hata işleme kodlarını, sanki set -eyürürlükte değillermiş gibi yazmakla kalmaz, aynı zamanda set -evar olmadıklarını düşünerek kandırmış olabilir.

Bazı başka dezavantajları set -e:

  • Özensiz kodu teşvik eder. Hata işleyicileri, unutulanların hatayı makul bir şekilde rapor etmeleri umuduyla tamamen unutulur. Ancak, let x++yukarıdaki gibi örneklerle , durum böyle değil. Komut beklenmedik bir şekilde ölürse, genellikle sessizce çalışır, bu hata ayıklamayı engeller. Senaryo ölmezse ve ummasını beklersen (önceki madde işaretine bakınız), o zaman ellerinde daha ince ve sinsi bir böcek vardır.
  • İnsanları sahte bir güvenlik hissine yönlendirir. Tekrar ifkondisyon mermi noktasına bakınız.
  • 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ış gösteren bir komut dosyası yazmak, set -ebu sürümler arasında ince ayar yapılması nedeniyle mümkündür .

set -eçekişmeli bir meseledir ve bazı insanlar çevreyi çevreleyen sorunların farkındayken, bazıları ise tuzakları bilmek aktifken dikkat etmeyi önerir. set -eTüm senaryolarda hata durumlarını yakalamalarını öneren pek çok shell komut dosyası yeniliği vardır , ancak gerçek hayatta bu şekilde çalışmaz.

set -e eğitim yerine geçmez.


2

Tehlikeli olduğunu söyleyebilirim çünkü senaryonun akışını artık kontrol etmiyorsun. Komut dosyası, komut dosyasının çağırdığı herhangi bir komut sıfır olmayan bir değer döndürdüğü sürece sona erebilir. Yani yapmanız gereken tek şey, bileşenlerin herhangi birinin davranışını veya çıktısını değiştiren bir şey yapmak ve ana betiği sonlandırmanız gerekiyor. Daha çok bir stil problemi olabilir, ama kesinlikle sonuçları var. Ya bu ana senaryonuz bir bayrak koymuşsa ve erken sona erdiği için olmasaydı? Bayrağın orada olması gerektiğini varsayarsa ya da beklenmedik bir varsayılan ya da eski bir değerle çalışıyorsa sistemin geri kalanına feragat ederdiniz.


Bu cevaba tamamen katılıyorum. Doğal olarak tehlikeli değil , ancak beklenmedik bir erken çıkış için bir fırsat.
ta 10:18

1
Bunun bana hatırlattığı şey, bir programda tek bir giriş noktası / tek bir çıkış noktası olmadığı için görevlerimden her zaman puan alan C ++ profesörlüğüm. Bunun tamamen “ilkeli” bir şey olduğunu düşündüm, ancak bu iş kesinlikle işlerin nasıl ve neden kontrolden tamamen çıkabileceğini gösteriyor. Nihayetinde programlar kontrol ve determinizm ile ilgilidir ve erken fesih ile her ikisinden de vazgeçersiniz.
Marcin

0

Beni kişisel olarak ısırmış @ Marcin'in cevabının daha somut bir örneği olarak rm foo/bar.txt, senaryonuzda bir yerde bir satır olduğunu hayal edin. foo/bar.txtAslında mevcut değilse , genellikle önemli bir şey yoktur. Ancak set -eşimdiki zamanla senaryonuz orada erken sona erecek! Hata.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.