Kabuk komut dosyalarının çıkış durumu için "ayrılmış" kodları kullanma


15

Geçenlerde Gelişmiş Bash-Scripting Kılavuzu'ndan Özel Anlamlarla Çıkış Kodları listesine rastladım . Bu kodlara ayrılmış olarak atıfta bulunurlar ve şunları önerirler :

Yukarıdaki tabloya göre, 1-2, 126-165 ve 255 çıkış kodlarının özel anlamları vardır ve bu nedenle kullanıcı tanımlı çıkış parametreleri için kaçınılmalıdır.

Bir süre önce, aşağıdaki çıkış durum kodlarını kullanan bir komut dosyası yazdım:

  • 0 - başarı
  • 1 - yanlış ana bilgisayar adı
  • 2 - geçersiz bağımsız değişkenler belirtildi
  • 3 - yetersiz kullanıcı ayrıcalıkları

Komut dosyasını yazdığımda, herhangi bir özel çıkış kodunun farkında değildim, bu yüzden ilk hata koşulu için 1'de başladım ve birbirini izleyen her hata türü için çıkış durumunu artırdım.

Ben daha sonraki bir aşamada (sıfır olmayan çıkış kodları için kontrol edebilir) diğer komut dosyaları tarafından çağrılabilir niyeti ile senaryo yazdı. Bunu henüz yapmadım; Şimdiye kadar sadece etkileşimli kabuğumdan (Bash) komut dosyasını çalıştırdım ve özel çıkış kodlarımı kullanarak herhangi bir sorunun neden olabileceğini merak ediyordum. Advanced Bash-Scripting Guide'ın önerisi ne kadar alakalı / önemlidir?

Bash belgelerinde destekleyici herhangi bir tavsiye bulamadım; Çıkış Durumu bölümü sadece Bash tarafından kullanılan çıkış kodlarını listeler, ancak bunlardan herhangi birinin ayrılmış olduğunu veya bunları kendi komut dosyalarınız / programlarınız için kullanmaya karşı uyarıldığını belirtmez.


6
Ben ve diğerleri, ABSG'nin genellikle düşük kalitede olduğunu düşünüyoruz. Kanımca, bağladığınız sayfanın yazarı, listelenen çıkış kodlarının, kabuğun kendisinin belirli anlamlar için kullandığı gerçeğine dayanarak, ayrılmış bir iddiada bulunuyor. Hiçbiri başarılı olamayan senaryolar için standartlar yaratma girişimleri olmuştur. Önemli olan, komut dosyalarınızın tüketicilerinin (örneğin diğer komut dosyaları) bunlara dayanarak ne yapılacağını bilmesi için seçtiğiniz hata kodlarını belgelemektir.
sonraki duyuruya kadar duraklatıldı.

@DennisWilliamson Yorumunuzu cevap olarak gönderirseniz, oyunuzu memnuniyetle bildiririz; Her birinin yararlı olduğunu bulduğum için diğer tüm cevapları zaten oyladım. Cevabınız içerik olarak David King'in (ve daha az bir ölçüde Zwol'ların) içeriğiyle benzer olsa da, ABSG alıntısında iddia için herhangi bir kanıt olmadığını açıkça belirtiyorsunuz.
Anthony Geoghegan

1
Teklif için teşekkürler, ancak yorumumun böyle kalması gerektiğine inanıyorum.
sonraki duyuruya kadar duraklatıldı.

O zamandan beri POSIX spesifikasyonunun benzer tavsiyeler içerdiğini keşfettim, bu yüzden bu bilgiyi kendi cevabıma ekledim (bu soruyu sorduğumdan bu yana araştırmamın sonuçlarını içeren).
Anthony Geoghegan

Yanıtlar:


10

İşlem çıkış kodlarının anlamlarını standartlaştırmak için birkaç girişimde bulunulmuştur. Bahsettiğinize ek olarak, şunları da biliyorum:

  • BSD'ler sysexits.h64'ten itibaren değerler için anlamları tanımlar.

  • grep0 kodundan çıkan GNU belgeleri, en az bir eşleşme bulunduğu, 1 eşleşme bulunmadığı ve 2, bir G / Ç hatasının oluştuğu anlamına gelir; bu kural, "hiçbir şey yanlış gitmedi, ancak hiçbir şey bulamadım" ve "bir G / Ç hatası oluştu" arasındaki farkın anlamlı olduğu diğer programlar için de yararlıdır.

  • C kütüphanesi fonksiyonunun birçok uygulaması system, programın mevcut olmadığını veya başlatılamadığını belirtmek için çıkış kodunu 127 kullanır.

  • Windows'ta, NTSTATUSkodlar (32-bit sayı alanının tümüne uygunsuz bir şekilde dağılmış olan) çıkış kodları olarak, özellikle de felaketle ilgili yanlış davranışlardan dolayı bir işlemin sonlandığını gösteren kodlar (örn. STATUS_STACK_OVERFLOW) Kullanılabilir.

Bu sözleşmelerden herhangi birine uyan belirli bir programa güvenemezsiniz. Tek güvenilir kural, çıkış kodu 0'ın başarılı olması ve başka bir şey bir çeşit başarısızlık olmasıdır. (C89 olduğunu Not EXIT_SUCCESSedilir değildir sıfır değerini için garanti, ancak exit(0)için aynı şekilde davranması için gereklidir exit(EXIT_SUCCESS). Değerler aynı olmasa bile)


Teşekkürler. Diğerlerine göre bir cevap seçmek zordu ama sorumu cevapladığım için bu cevabı kabul ediyorum, aynı zamanda kullanımdaki farklı çıkış kodlarının geniş bir lezzetini de sağlıyor (ilgili bağlantılar ile): 3'ten fazla hakkı hak ediyor şu anda var.
Anthony Geoghegan

11

Hiçbir çıkış kodu özel bir anlamı vardır, ama değer $?özel bir anlama sahip olabilir.

Bourne Shell ve ksh93'ün çıkış kodlarını ve hata durumlarını shell değişkenine işleme ve iletme şekli $?problemdir. Listelediklerinizin aksine, yalnızca aşağıdaki değerlerin $?özel bir anlamı vardır:

  • 126 İkili olsa bile çalıştırılamadı
  • 127 Belirtilen ikili dosya yok
  • 128 çıkış durumu == 0, ancak belirtilmemiş bazı sorunlar var

Ayrıca, $?bir sinyal tarafından kesilen bir program için ayrılmış, tanımlanmamış bir kabuk ve platforma özgü kod aralığı > 128 vardır:

  • Bourne Shell bash ve ksh88 128 + sinyal numarası kullanır
  • ksh93 256 + sinyal numarasını kullanır.

Diğer değerler kabuk-özel $?değerlerinden ayırt edilebileceği için problem oluşturmazlar .

Özellikle, 1 ve 2 değerleri özel koşullar için kullanılmaz, sadece yerleşik olmadığında aynı davranabilen yerleşik komutlar tarafından kullanılan çıkış kodlarıdır. Bu nedenle, sağladığınız bash komut dosyası kılavuzuna işaretçi, belirli bir kodun kendi komut dosyaları için kaçınılması gereken özel bir değer olup olmadığını açıklamadan bash tarafından kullanılan kodları listelediği için iyi bir kılavuz değildir.

Bourne Shell'in daha yeni sürümleri , programın çıkmasını beklemek waitid()yerine kullanıyor waitpid()ve waitid()(SVr4 için 1989 tanıtıldı) daha iyi bir sistem ara yüzü kullanıyor (UNOS'un 1980'de kullandığı şeye benzer).

Yeni Bourne Shell versiyonları kodlamak üzere çıkış nedenini ayrı değişkene ${.sh.code}/ ${.sh.codename}den çıkış kodu ise ${.sh.status}/ ${.sh.termsig}Görmekten http://schillix.sourceforge.net/man/man1/bosh.1.html , çıkış kodu aşırı değildir Özel durumları olan ve `waitid () kullanmanın bir sonucu olarak, Bourne Kabuğu artık sadece düşük 8 bitin değil, 32 bitin çıkış kodunun döndürülmesini destekliyor.

BTW: Klasik bir kabukta 0 olarak yorumlanmasına yol exit(256)açtığından, bir C-programına veya kabuk betiğine benzer veya onlardan $?benzemeyin.


2
BTW: waitid()Mayıs ayı sonunda FreeBSD ve Linux çekirdeğine karşı bir hata raporu hazırladım . FreeBSD halkı 20 saat içinde sorunu çözdü, Linux halkı hatalarını düzeltmekle ilgilenmiyor. ... ve Cygwin halkı,
hatalarla

2
Bu davranış, Tekli Unix Spesifikasyonu tarafından gereklidir . 32 bitlik bir değer var, evet, ancak bu değer, değerin düşük 8 bitini içeren 8 bitlik bir bit alanı içeriyor _exit. Lütfen bahsettiğiniz FreeBSD hata raporunu bağlayın, belki tanımladığınız sorunu yanlış anlıyorum.
Random832

2
OP soruyu bash ile etiketledi ve sorunun metninde Bash'ten bahsetti. Bash, Bourne'den türetilmiş bir kabuktur. ${.sh.}Değişkenleri desteklemez . Bununla birlikte, "Bourne'den türetilmiş" değil "Bourne" dediğiniz doğrudur (ksh93'ü dahil etmenize rağmen).
sonraki duyuruya kadar duraklatıldı.

2
Bu yanıt, bazı SVR4'ten türetilmiş Unix'lerin özel varyantınıza çok özel görünüyor. V7'de olanı kastetmedikçe, neyin taşınabilir ve neyin olmadığı konusunda daha net olun, "Bourne kabuğu" diye bir şey olmadığını unutmayın.
Zwol

4
Aksine, buradaki varyasyon aralığını, özellikle de tarihsel varyasyonu anlayanın siz olduğuna inanıyorum. /bin/shBu özel çıkış kodları çapraz platform için sürekli davranmaya güvenilebileceği gibi geliyor , bu doğru değil. ( Herhangi bir sistemin "gerçek Bourne kabuğu" olarak söylenip söylenemeyeceği umrumda değil /bin/sh. Bunların hiçbirinin POSIX'te olmadığını ve "gerçek Unix sistemleri" olarak "belirttiğiniz şeylerin çoğunun t POSIX uyumlu /bin/shzaten.)
zwol

6

Kabuk komut dosyaları için, bazen adlandırdığım sysexist.hkabuk ayrılmış çıkış kodlarıyla (ön ekli S_EX_) kabuk eşdeğerini kaynak olarak alıyorumexit.sh

Temel olarak:

EX_OK=0 # successful termination 
EX__BASE=64     # base value for error messages 
EX_USAGE=64     # command line usage error 
EX_DATAERR=65   # data format error 
EX_NOINPUT=66   # cannot open input 
EX_NOUSER=67    # addressee unknown 
EX_NOHOST=68    # host name unknown 
EX_UNAVAILABLE=69       # service unavailable 
EX_SOFTWARE=70  # internal software error 
EX_OSERR=71     # system error (e.g., can't fork) 
EX_OSFILE=72    # critical OS file missing 
EX_CANTCREAT=73 # can't create (user) output file 
EX_IOERR=74     # input/output error 
EX_TEMPFAIL=75  # temp failure; user is invited to retry 
EX_PROTOCOL=76  # remote error in protocol 
EX_NOPERM=77    # permission denied 
EX_CONFIG=78    # configuration error 
EX__MAX=78      # maximum listed value 

#System errors
S_EX_ANY=1      #Catchall for general errors
S_EX_SH=2       #Misuse of shell builtins (according to Bash documentation); seldom seen
S_EX_EXEC=126   #Command invoked cannot execute         Permission problem or command is not an executable
S_EX_NOENT=127  #"command not found"    illegal_command Possible problem with $PATH or a typo
S_EX_INVAL=128  #Invalid argument to exit       exit 3.14159    exit takes only integer args in the range 0 - 255 (see first footnote)                                                                                        
#128+n  Fatal error signal "n"  kill -9 $PPID of script $? returns 137 (128 + 9)                               
#255*   Exit status out of range        exit -1 exit takes only integer args in the range 0 - 255              
S_EX_HUP=129                                                                                                   
S_EX_INT=130   
#...

Ve şunlarla oluşturulabilir:

#!/bin/sh
src=/usr/include/sysexits.h
echo "# Generated from \"$src\"" 
echo "# Please inspect the source file for more detailed descriptions"
echo
< "$src" sed -rn 's/^#define  *(\w+)\s*(\d*)/\1=\2/p'| sed 's:/\*:#:; s:\*/::'
cat<<'EOF'

#System errors
S_EX_ANY=1  #Catchall for general errors
S_EX_SH=2   #Misuse of shell builtins (according to Bash documentation); seldom seen
S_EX_EXEC=126   #Command invoked cannot execute     Permission problem or command is not an executable
S_EX_NOENT=127  #"command not found"    illegal_command Possible problem with $PATH or a typo
S_EX_INVAL=128  #Invalid argument to exit   exit 3.14159    exit takes only integer args in the range 0 - 255 (see first footnote)
#128+n  Fatal error signal "n"  kill -9 $PPID of script $? returns 137 (128 + 9)
#255*   Exit status out of range    exit -1 exit takes only integer args in the range 0 - 255
EOF
$(which kill) -l |tr ' ' '\n'| awk '{ printf "S_EX_%s=%s\n", $0, 128+NR; }'

Ama çok fazla kullanmıyorum, ama ne kullandığım dize biçimlerine hata kodlarını tersine çeviren bir kabuk işlevidir. Ben adını verdim exit2str. Yukarıdaki adlandırdığınız varsayarsak exit.shjeneratör exit.sh.sh, kodu exit2str(ile oluşturulabilir exit2str.sh.sh):

#!/bin/sh
echo '
exit2str(){
  case "$1" in'
./exit.sh.sh | sed -nEe's|^(S_)?EX_(([^_=]+_?)+)=([0-9]+).*|\4) echo "\1\2";;|p'
echo "
  esac
}"

Ben bu kullanmak PS1benim interaktif kabuğun böylece (bilinen bir dize form var yoksa) Ben koşmak her komutun ardından, onun çıkış durumu ve dize formunu görebilirsiniz:

[15:58] pjump@laptop:~ 
(0=OK)$ 
[15:59] pjump@laptop:~ 
(0=OK)$ fdsaf
fdsaf: command not found
[15:59] pjump@laptop:~ 
(127=S_NOENT)$ sleep
sleep: missing operand
Try 'sleep --help' for more information.
[15:59] pjump@laptop:~ 
(1=S_ANY)$ sleep 100
^C
[15:59] pjump@laptop:~ 
(130=S_INT)$ sleep 100
^Z
[1]+  Stopped                 sleep 100
[15:59] pjump@laptop:~ 
(148=S_TSTP)$

Bunları elde etmek için, exit2str işlevi için kaynak sağlanamaması gerekir:

$ ./exit2str.sh.sh > exit2str.sh #Place this somewhere in your PATH

ve ardından ~/.bashrcher komut isteminde çıkış kodunu kaydetmek ve çevirmek için bunu kullanın ve isteminizi görüntüleyin ( PS1):

    # ...
    . exit2str.sh
PROMPT_COMMAND='lastStatus=$(st="$?"; echo -n "$st"; str=$(exit2str "$st") && echo "=$str"); # ...'
    PS1="$PS1"'\n($lastStatus)\$'
    # ...                                                                                   

Bazı programların çıkış kodu kurallarına nasıl uyduğunu gözlemlemek, bazılarının çıkış kodu kurallarını öğrenmek veya sadece neler olduğunu daha kolay görebilmek için oldukça kullanışlıdır. Bir süredir kullandığım için, sistem odaklı birçok kabuk komut dosyasının kuralları takip ettiğini söyleyebilirim. EX_USAGEdiğer kodlar çok olmasa da özellikle oldukça yaygındır. Zaman zaman sözleşmeleri takip etmeye çalışıyorum, $S_EX_ANYtembel insanlar için (1) her zaman (1) var.


Bir errno kodu ve bu errno kodu ile bildirilen hata bir hata çıkışı sonuçlanırsa kullanmak için bir çıkış kodu arasında bir eşleşme gibi bir şey olup olmadığını merak ediyorum. Biraz makul bir harita bulmam gerekebilir.
PSkocik

1
Vaov! Böyle ayrıntılı bir cevap beklemiyordum. Bunu kesinlikle farklı komutların nasıl davrandığını görmek için iyi bir yol olarak deneyeceğim. Teşekkürler.
Anthony Geoghegan

4

Çıkış kodlarınızı belgelediğiniz sürece, bir yıl sonra geri dönüp senaryoyu düzeltmeniz gerektiğinde bunları hatırlamanız gerekir. "Ayrılmış çıkış kodları" fikri, 0bir başarı kodu ve bir başarısızlık kodu olarak başka bir şey kullanmanın geleneksel olduğunu söylemek dışında artık geçerli değildir .


4

Bulabildiğim en iyi referans şuydu: http://tldp.org/LDP/abs/html/exitcodes.html

Buna göre:

1 hatalar için genel bir catchall ve her zaman kullanıcı tanımlı hatalar için kullanıldığını gördüm.

2 sözdizimi hatası gibi kabuk yerleşiklerinin kötüye kullanılması içindir

Sorunuzu doğrudan cevaplamak için, komut dosyanız ayrılmış hata kodlarını kullanarak iyi olacak, hatayı = 1/2/3 hata koduna göre ele aldığınızı varsayarsa beklendiği gibi çalışacaktır.

Ancak, ayrılmış hata kodlarını bilen ve kullanan biriyle karşılaşırsanız, bu oldukça nadir görünen kafa karıştırıcı olabilir.

Kullanabileceğiniz bir başka seçenek de, varsa, yankı ve sonra çıkın, betiğinizin "hiçbir haber iyi haber değildir" ve echo'nun başarıdaki hiçbir şeyinin Linux kuralına uymadığını varsayarak.

if [ $? -ne 0 ];then
    echo "Error type"
    exit 1
fi

2

Aldığım cevaplara dayanarak (diğerlerinden birini seçmek zor oldu), Bash'in de kullandığı bir çıkış kodunu kullanarak belirli hata türlerini belirtmek zararlı değildir . Bir kullanıcı komut dosyası bu hata kodlarından biriyle çıkarsa Bash (veya başka bir Unix kabuğu) özel bir şey yapmaz (istisna işleyicileri çalıştırmak gibi).

Gelişmiş Bash-Scripting Guide'ın yazarının BSD çıkış kodlarını standartlaştırmaya çalıştığını ( sysexits.h) kabul ettiği ve basitçe kullanıcılar kabuk komut dosyaları yazdıklarında, önceden tanımlanmış çıkış kodlarıyla çakışan çıkış kodlarını belirtmemelerini önerir . kullanımda, yani özel çıkış kodlarını 64-113 aralığındaki 50 durum koduyla sınırlarlar.

Fikri (ve mantığı) takdir ediyorum, ancak yazarın tavsiyeyi görmezden gelmenin zararlı olmadığı daha açık olsaydı, bir komut dosyası tüketicisinin belirtilen örnek gibi hataları kontrol ettiği durumlar dışında tercih ederdim. ( command not found).

İlgili POSIX spesifikasyonları

POSIX'in çıkış kodları hakkında söylediklerini araştırdım ve POSIX spesifikasyonu Gelişmiş Bash-Scripting Guide'ın yazarıyla aynı fikirde görünüyor. İlgili POSIX spesifikasyonlarından alıntı yaptım (benimkini vurgulayın):

Komutlar için Çıkış Durumu

Her komutun diğer kabuk komutlarının davranışını etkileyebilecek bir çıkış durumu vardır. Yardımcı olmayan komutların çıkış durumu bu bölümde belgelenmiştir. Standart yardımcı programların çıkış durumu ilgili bölümlerinde belgelenmiştir.

Bir komut bulunamazsa, çıkış durumu 127 olur. Komut adı bulunur ancak yürütülebilir bir yardımcı program değilse, çıkış durumu 126 olur. Kabuğu kullanmadan yardımcı programları çağıran uygulamalar bu çıkış durumu değerlerini kullanmalıdır benzer hataları bildirmek için.

Sözcük genişletme veya yönlendirme sırasında bir komut başarısız olursa, çıkış durumu sıfırdan büyük olacaktır.

Dahili olarak, bir komutun sıfırdan farklı olmayan çıkış durumuyla çıkıp çıkmadığına karar vermek amacıyla, kabuk komut için alınan tüm durum değerini WEXITSTATUS makrosunun (Sistem Arabirimleri biriminde tanımlandığı gibi) eşdeğeriyle tanıyacaktır. POSIX.1-2008). Çıkış durumu '?' Özel parametresi ile raporlanırken, kabuk mevcut sekiz çıkış durumunun tamamını bit olarak bildirecektir. Bir sinyal aldığı için sonlandırılan bir komutun çıkış durumu 128'den büyük olarak rapor edilecektir.

Yardımcı exitprogram

Diğer bölümlerde açıklandığı gibi, belli çıkış durumu değerleri olan saklıdır özel kullanımlar için ve gerektiği yalnızca bu amaçlar için uygulamalar tarafından kullanılacak:

  • 126 - Yürütülecek bir dosya bulundu, ancak yürütülebilir bir yardımcı program değildi.
  • 127 - Yürütülecek bir yardımcı program bulunamadı.
  • >128 - Bir komut bir sinyal tarafından kesildi.

Daha fazla bilgi

Değer için, Özel Anlamlarla Çıkış Kodları listesinden biri hariç hepsini doğrulayabildim . Bu çıkış kodları tablosu, Bash referansında belgelenen hata kodlarının nasıl oluşturulacağına ilişkin daha fazla ayrıntı ve örnekler sağladığından faydalıdır .

128 çıkış durumu oluşturulmaya çalışıldı

Bash 3.2.25 ve 4.2.46 sürümlerini kullanarak, bir 128 Invalid argument to exithata atmaya çalıştım, ancak her 255 aldığımda (Çıkış durumu aralık dışında). Örneğin, exit 3.14159bir kabuk betiğinin parçası olarak veya etkileşimli bir alt kabukta yürütülürse, kabuk şu kodla çıkar 255:

$ exit 3.14159
exit
bash: exit: 3.14159: numeric argument required

Daha da eğlenmek için, basit bir C programı çalıştırmayı denedim, ancak bu durumda, exit(3)fonksiyon çıkmadan önce şamandırayı bir int'e (bu durumda 3) dönüştürdüğü görülüyor :

#include <stdlib.h>
main()
{
    exit(3.14159);
}
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.