İşlem sonlandırıldığında varsayılan çıkış kodu?


54

Bir işlem, gibi bir işlemle başlayabilen bir sinyalle öldürüldüğünde SIGINTveya SIGTERMbu sinyali ele almıyorsa, işlemin çıkış kodu ne olur?

Peki ya engelsiz sinyaller gibi SIGKILL?

Söyleyebileceğim, SIGINTçıkış kodu muhtemel sonuçları olan bir işlemi öldürmek 130, ancak bu çekirdek veya kabuk uygulamasına göre değişebilir mi?

$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130

Diğer sinyalleri nasıl test edeceğimi bilmiyorum ...

$ ./myScript &
$ killall myScript
$ echo $?
0  # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0  # same problem

1
senin killall myScriptdolayısıyla dönüş çalışmaları, killall ait (ve senaryonun!) 'dir 0. Bir yer verebilir kill -x $$sh çalışır (sinyal numarası olma x [ve $$ genellikle bu komut dosyasının PID kabuk tarafından genişletilmiş, bash, ...)] betiğin içinde ve sonra çıkış çekirdeğinin ne olduğunu test edin.
Olivier Dulac


Yarı soru hakkında yorum yapma: MyScript'i arkaplana koymayın. (atlamak &). Sinyali başka bir kabuk işleminden (başka bir terminalde) $?gönderin, sonra myScript bittikten sonra kullanabilirsiniz .
MattBianco

Yanıtlar:


61

İşlemler, _exit()sistem çağrısını (Linux'ta da bakınız exit_group()) ebeveynlerine bir çıkış kodu bildirmek için bir tamsayı argümanıyla çağırabilir . Bir tamsayı olmasına rağmen, ebeveyn için yalnızca en az 8 önemli bit bulunur (bunun istisnası , Linux'ta olmasa da, kodu almak için üstte SIGCHLD kullanırken waitid()veya işleyici olduğunda ).

Ebeveyn genellikle bir tamsayı olarak çocuğunun statüsünü almak için wait()veya waitpid()yapar ( biraz farklı anlambilimiyle de olsa kullanılabilir).waitid()

Linux ve çoğu Unices, işlem normal şekilde sonlandırılırsa, bu durum numarasının 8 ila 15 bitleri , iletildiği gibi çıkış kodunu içerir exit(). Aksi takdirde, en az 7 önemli bit (0 ila 6) sinyal numarasını içerecek ve bir çekirdek dökülmüşse bit 7 ayarlanacaktır.

perlVar $?tarafından belirlenen, örneğin, bu sayı içerir waitpid():

$ perl -e 'system q(kill $$); printf "%04x\n", $?'
000f # killed by signal 15
$ perl -e 'system q(kill -ILL $$); printf "%04x\n", $?'
0084 # killed by signal 4 and core dumped
$ perl -e 'system q(exit $((0xabc))); printf "%04x\n", $?'
bc00 # terminated normally, 0xbc the lowest 8 bits of the status

Bourne benzeri mermiler de son çalıştırma komutunun çıkış durumunu kendi $?değişkenlerinde yapar. Bununla birlikte, doğrudan döndürdüğü sayıyı içermez waitpid(), ancak üzerinde bir dönüşüm içerir ve kabukları arasında farklıdır.

Tüm kabuklar arasında ortak olan , işlem normal şekilde sonlandırıldığı takdirde $?çıkış kodunun en düşük 8 bitini (geçen sayı exit()) içermesidir .

Farklı olduğu yerde işlem bir sinyal ile sonlandırılır. Her durumda ve bu POSIX tarafından isteniyorsa, sayı 128'den büyük olacaktır. POSIX, değerin ne olabileceğini belirtmez. Uygulamada, bildiğim tüm Bourne benzeri mermilerde, en düşük 7 bit $?sinyal numarasını içerecek. Ancak, nsinyal numarası nerede

  • kül, zsh, pdksh, deneme, Bourne kabuğu, $?bir 128 + n. Bunun anlamı bir alırsanız o kabuklarda, yani $?bir 129, sen süreci ile çıkıldı çünkü öyle olmadığını bilmiyorum exit(129)ya da sinyal tarafından öldürüldüğü olmadığını 1( HUPen sistemlerde). Ancak bunun sebebi, kendiliğinden çıktıklarında kabukların varsayılan olarak en son çıkılan komutun çıkış durumunu döndürmesidir. $?Asla 255'ten büyük olmadığından emin olarak , tutarlı bir çıkış durumuna sahip olmanızı sağlar:

    $ bash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    bash: line 1: 16720 Terminated              sh -c "kill \$\$"
    8f # 128 + 15
    $ bash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
    bash: line 1: 16726 Terminated              sh -c "kill \$\$"
    8f # here that 0x8f is from a exit(143) done by bash. Though it's
       # not from a killed process, that does tell us that probably
       # something was killed by a SIGTERM
    
  • ksh93, $?Olduğu 256 + n. Bu, $?sizin değerinizden, öldürülen ve öldürülmeyen bir süreç arasında ayrım yapabileceğiniz anlamına gelir . kshÇıkışta $?255'ten büyük olsaydı daha yeni sürümleri , aynı çıkış durumunu ebeveyne bildirmek için kendisini aynı sinyalle öldürür. Bu iyi bir fikir gibi görünse de, ksheğer süreç bir çekirdek üretme sinyali tarafından öldürüldüyse, ekstra bir çekirdek dökümü (potansiyel olarak diğeri üzerine yazma) oluşturacak demektir:

    $ ksh -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    ksh: 16828: Terminated
    10f # 256 + 15
    $ ksh -c 'sh -c "kill -ILL \$\$"; exit'; printf '%x\n' "$?"
    ksh: 16816: Illegal instruction(coredump)
    Illegal instruction(coredump)
    104 # 256 + 15, ksh did indeed kill itself so as to report the same
        # exit status as sh. Older versions of `ksh93` would have returned
        # 4 instead.
    

    Bir hatanın olduğunu söyleyebileceğiniz yer , bir işlev tarafından ksh93yapılsa bile kendisini öldüren $?bir return 257şey:

    $ ksh -c 'f() { return "$1"; }; f 257; exit'
    zsh: hangup     ksh -c 'f() { return "$1"; }; f 257; exit'
    # ksh kills itself with a SIGHUP so as to report a 257 exit status
    # to its parent
    
  • yash. yashbir uzlaşma sunar. Döner 256 + 128 + n. Bu, öldürülen bir işlem ile doğru bir şekilde sonlanan bir işlem arasında da farklılaşabileceğimiz anlamına gelir. Çıktıktan sonra, 128 + nkendisini ve sahip olabileceği yan etkileri intihar etmek zorunda kalmadan rapor verecek .

    $ yash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    18f # 256 + 128 + 15
    $ yash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
    8f  # that's from a exit(143), yash was not killed
    

Sinyal değerini almak için $?, taşınabilir yol kullanmaktır kill -l:

$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM

(taşınabilirlik için asla sinyal numaraları kullanmamalısınız, sadece sinyal isimleri kullanmalısınız)

Bourne olmayan cephelerde:

  • csh/ tcshVe fishdurum olduğunu dışında Bourne kabuğunun aynı $statusyerine $?(Not zshda ayarlar $statusile uyumluluk için csh(ek olarak $?)).
  • rc: çıkış durumu $statusda var, ancak bir sinyal tarafından öldürüldüğünde, bu değişken bir numara yerine sinyalin adını ( bir çekirdek üretildiyse sigtermveya sigill+coreüretildiyse) içerir, bu da kabuğun iyi tasarımının bir başka kanıtıdır. .
  • es. çıkış durumu değişken değil. Bunu umursuyorsanız, komutu şu şekilde çalıştırın:

    status = <={cmd}
    

    hangi bir sayı sigtermveya sigsegv+corebenzeri döndürecek rc.

Belki şeyiyle biz belirtmeliyim zsh's $pipestatusve bash' ın $PIPESTATUSson boru hattının bileşenlerinin çıkış durumu ihtiva diziler.

Ve ayrıca bütünlük için, kabuk işlevlerine ve kaynak dosyalara gelince, varsayılan işlevler en son komut çalıştırmasının çıkış durumuyla birlikte döner, ancak returnyerleşik olarak açıkça bir dönüş durumu da ayarlayabilir . Ve burada bazı farklılıklar görüyoruz:

  • bashve mksh( R41'den bu yana, kasıtlı olarak tanıtılan bir Wchange ^ gerilimi ) sayıyı (pozitif veya negatif) 8 bit olarak kısaltacaktır. Yani örneğin return 1234koyacaktır $?için 210, return -- -1ayarlayacaktır $?255.
  • zshve pdksh(ve dışındaki türevler mksh) işaretli bir 32 bit ondalık tamsayıya izin verir (-2 31 ila 2 31 -1) (ve sayıyı 32 bit olarak kesin).
  • ashve yash0 ila 2 31 -1 arasındaki herhangi bir pozitif tamsayıya izin verin ve bunun dışındaki herhangi bir sayı için bir hata döndürün.
  • ksh93için return 0için return 320ayarlanmış $?olduğu gibi, ama başka bir şey için, 8 bite kesecek. Daha önce de belirtildiği gibi, 256 ile 320 arasında bir sayı döndürmenin kshçıkıştan sonra kendini öldürmesine neden olabileceğine dikkat edin .
  • rcve eshatta listeler bile bir şeyleri iade izin verir.

Ayrıca bazı kabukları da özel değerleri kullanmak unutmayın $?/ $statusgibi bir sürecin çıkış durumu olmayan bazı hata durumlarını bildirmek 127veya 126için bulunmayan komut veya değil çalıştırılabilir (a kaynaklı dosyasında veya sözdizimi hatası) ...


1
an exit code to their parentve to get the *status* of their child. "durum" a vurgu yaptınız. Mı exit codeve *status*aynı? Vaka evet, iki isme sahip olmanın kökeni nedir? Durum aynı değil, durum tanımı / referansı verebilir misiniz?
n611x007

2
Burada 3 numara var. Çıkış kodu : geçirilen numara exit(). Çıkış durumu : ile elde edilen sayı waitpid()olan çıkış kodu, sinyal dizi içerir ve mevcut olup olmadığı bir çekirdek terk etti. Bazı kabukların , çıkış durumunun normal bir fesih olması durumunda çıkış kodunu içerecek şekilde dönüştürmesi gibi özel değişkenlerinden ( $?, $status) elde ettiği sayı ( ve ); süreç öldürüldü (buna genel olarak çıkış durumu da denir ). Hepsi benim cevabımda açıklandı.
Stéphane Chazelas

1
Anladım teşekkür ederim! Buradaki ayrımın bu açık notunu kesinlikle takdir ediyorum. Çıkışa ilişkin bu ifadeler, yapmaya değer olduğu bazı yerlerde birbirinin yerine kullanılır. Kabuk değişkeni değişkeninin (genel) bir adı bile var mı? Bu nedenle , mermilerle ilgili ayrıntılara girmeden önce açıkça temizlemenizi öneririm . İlk veya ikinci paragraftan sonra açıklamayı (yorumunuzdan) eklemenizi öneririm.
n611x007

1
İlk 7 bitin sinyal olduğu hakkında yazan POSIX fiyat teklifine işaret edebilir misiniz? Tek bulabildiğim > 128kısım: "Bir sinyal aldığı için sonlanan bir komutun çıkış durumu 128'den büyük olarak raporlanacak." pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Ciro Santilli,

1
@cuonglm, HTTP üzerinden başka hiçbir yerde kullanıma açık olduğunu sanmıyorum, hala NNTP üzerinden gmane'den alabilirsiniz. Mesaj kimliğini arayın efe764d811849b34eef24bfb14106f61@austingroupbugs.net(2015-05-06 arasında) veyaXref: news.gmane.org gmane.comp.standards.posix.austin.general:10726
Stéphane Chazelas

23

Bir işlem çıktığında, işletim sistemine bir tamsayı değeri döndürür. Çoğu unix varyantında bu değer modulo 256 olarak alınmıştır: düşük sıra bitleri hariç her şey göz ardı edilir. Bir alt sürecin durumu, içinde 16 bitlik bir tamsayı ile ebeveyne döndürülür.

  • 0-6 bitleri (7 düşük dereceli bit), işlemi öldürmek için kullanılan sinyal numarası veya işlem normal şekilde çıkmışsa 0;
  • bit 7, eğer işlem bir sinyal ve atılan çekirdek tarafından öldürülmüşse ayarlanır;
  • 8 ile 15 arasındaki bitler, işlem normal şekilde çıkarsa işlemin çıkış kodudur veya işlem bir sinyal tarafından öldürüldüyse 0'dır.

Durum waitsistem çağrısı veya kardeşlerinden biri tarafından geri döndürülür . POSIX, çıkış durumunun ve sinyal numarasının tam olarak kodlanmasını belirtmez; sadece sağlar

  • çıkış durumunun bir sinyale mi yoksa normal çıkışa mı karşılık geldiğini söylemenin bir yolu;
  • işlem normal şekilde çıktıysa, çıkış koduna erişmenin bir yolu;
  • İşlem bir sinyal tarafından öldürülmüşse, sinyal numarasına erişmenin bir yolu.

Açıkçası, bir işlem bir sinyal tarafından öldürüldüğünde çıkış kodu yoktur : bunun yerine çıkış durumu vardır .

Bir kabuk komut dosyasında, bir komutun çıkış durumu özel değişken aracılığıyla bildirilir $?. Bu değişken çıkış durumunu belirsiz bir şekilde kodlar:

  • İşlem normal bir şekilde çıkıldıysa $?çıkış durumu.
  • İşlem bir sinyal tarafından öldürülmüşse $?, çoğu sistemde 128 artı sinyal numarasıdır. POSIX $?, bu durumda yalnızca 128'den büyük olan mandaları ; ksh93, 128 yerine 256 ekliyor. Sinyal numarasına bir sabit eklemek dışında hiçbir şey yapmayan bir unix çeşidi görmedim.

Dolayısıyla bir kabuk betiğinde bir komutun bir sinyal tarafından öldürüldüğünü veya ksh93 dışında 128'den büyük bir durum koduyla çıkıldığını kesin olarak söyleyemezsiniz. Programların 128'den büyük durum kodlarıyla çıkmaları çok nadir görülür, çünkü programcılar $?belirsizlikten kaçınırlar .

SIGINT çoğu unix varyantında sinyal 2'dir, bu nedenle $?SIGINT tarafından öldürülen bir işlem için 128 + 2 = 130'dur. SIGHUP için 129, SIGKILL için 137, vb.


Aynı şeyleri söylese bile, benimkinden çok daha iyi ifade etti ve ifade etti. Bunun $?sadece Bourne benzeri kabukları için olduğunu açıklamak isteyebilirsiniz . Ayrıca bkz yashfarklı (ama yine de POSIX) davranış. Ayrıca POSIX + XSI'ye (Unix) göre a kill -2 "$pid", işleme bir SIGINT gönderir, ancak gerçek sinyal numarası 2 olmayabilir, bu yüzden $? mutlaka 128 + 2 (veya 256 + 2 veya 384 + 2) kill -l "$?"olmayacak , yine de geri dönecek INT, bu yüzden taşınabilirlik için numaraların kendilerine atıfta bulunmamalarını tavsiye ediyorum.
Stéphane Chazelas

8

Bu kabuğuna bağlı. Gönderen bash(1)adam sayfasında, KABUK GRAMER bölümünde, Basit Komutlar alt bölüm:

Komutun n sinyali ile sonlandırılması durumunda basit bir komutun dönüş değeri [...] 128+ n'dir .

Yana SIGINTsisteminizde sinyal sayısı 2'dir, dönüş değeri o Bash altında çalıştırılır 130 olduğunu.


1
Bunu dünyada nasıl buluyorsun ya da nereye bakacağını bile biliyorsun? Senin dehasından önce eğildim.
Cory Klein

1
@CoryKlein: Deneyim, çoğunlukla. Oh, muhtemelen signal(7)man sayfasını da isteyeceksiniz .
Ignacio Vazquez-Abrams

güzel şeyler; C'ye bu sabitleri içeren tesadüfen dosyaları dahil edip etmediğimi biliyor musunuz? +1
Rui F Ribeiro,

@CoryKlein Neden bunu doğru cevap olarak seçmediniz?
Rui F Ribeiro

3

SVr4'ün 1989'da waitid () 'ı tanıttığını söylemek için doğru yer gibi görünüyor, ancak bugüne kadar önemli bir program kullanmıyor gibi görünüyor. waitid (), 32 bitin tümünün exit () kodundan almasına izin verir.

Yaklaşık 2 ay önce Bourne Kabuğunun bekle / iş kontrol bölümünü waitpid () yerine waitid () kullanacak şekilde yeniden yazdım. Bu, çıkış kodunu 0xFF ile maskeleyen sınırlamayı kaldırmak için yapıldı.

Waitid () arayüzü, 1980'den itibaren UNOS'tan cwait () çağrısında belirtilen önceki wait () uygulamalarında daha temizdir.

Man sayfasını okumak için ilginizi çekebilir:

http://schillix.sourceforge.net/man/man1/bosh.1.html

ve şu anda 8. sayfaya bakmakta olan "Parametre Değiştirme" bölümünü kontrol edin.

Yeni değişkenler .sh. * Waitid () arayüzü için tanıtıldı. Bu arayüz artık $ için bilinen rakamlar için belirsiz anlamlar taşımamaktadır. ve arayüzlemeyi çok daha kolaylaştırır.

Bu özelliği kullanabilmek için POSIX uyumlu bir waitid () uygulamanız gerektiğini unutmayın; bu nedenle Mac OS X ve Linux şu anda bunu sunmuyor, ancak waitid () çağrısında waitid () öykünüyor POSIX dışı platformda hala çıkış kodundan sadece 8 bit alacaksınız.

Kısacası: .sh.status sayısal çıkış kodu, .sh.code sayısal çıkış nedenidir.

Daha iyi taşınabilirlik için, çıkış nedeninin metinsel sürümü için .sh.codename, örneğin "DUMPED" ve .sh.termsig, işlemi sonlandıran sinyalin adıdır.

Daha iyi kullanım için, çıkışla ilgili olmayan .sh.codename değerleri vardır: bir programın başlatılamaması durumunda kullanılan "NOEXEC" ve "NOTFOUND".

FreeBSD raporumdan sonraki 20 saat içinde waitid () kerlnel hatasını düzeltti, Linux henüz düzeltmeye başlamadı. Umarım POSIX'teki bu özelliği tanıttıktan 26 yıl sonra, tüm işletim sistemleri yakında bunu destekleyecektir.


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.