GNU/Linux >> Znalost Linux >  >> Linux

Výchozí kód ukončení při ukončení procesu?

Když je proces zabit signálem, který lze ovládat, jako je SIGINT nebo SIGTERM ale nezpracovává signál, jaký bude výstupní kód procesu?

A co pro nezvládnutelné signály jako SIGKILL ?

Z toho, co vím, zabíjení procesu pomocí SIGINT pravděpodobně vyústí v ukončovací kód 130 , ale lišilo by se to podle implementace jádra nebo shellu?

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

Nejsem si jistý, jak bych otestoval ostatní signály…

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

Přijatá odpověď:

Procesy mohou volat _exit() systémové volání (v Linuxu viz také exit_group() ) s celočíselným argumentem pro nahlášení výstupního kódu jejich rodiči. Ačkoli se jedná o celé číslo, nadřazenému prvku je k dispozici pouze 8 nejméně významných bitů (výjimkou je použití waitid() nebo handler na SIGCHLD v nadřazeném nástroji pro načtení tohoto kódu, i když ne na Linuxu).

Rodič obvykle provede wait() nebo waitpid() získat stav jejich potomka jako celé číslo (ačkoli waitid() s poněkud odlišnou sémantikou lze také použít).

V Linuxu a většině Unices, pokud byl proces ukončen normálně, bity 8 až 15 tohoto stavu number bude obsahovat návratový kód předaný do exit() . Pokud ne, pak 7 nejméně významných bitů (0 až 6) bude obsahovat číslo signálu a bit 7 bude nastaven, pokud bylo jádro vyhozeno.

perl 's $? například obsahuje toto číslo nastavené pomocí waitpid() :

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

Shelly podobné Bourneovi také vytvářejí stav ukončení posledního spuštěného příkazu ve svém vlastním $? variabilní. Neobsahuje však přímo číslo vrácené funkcí waitpid() , ale je na něm transformace a mezi shelly je to jiné.

Co je společné mezi všemi shelly, je to, že $? obsahuje nejnižších 8 bitů výstupního kódu (číslo předané do exit() ), pokud byl proces ukončen normálně.

Kde se liší je, když je proces ukončen signálem. Ve všech případech, a to vyžaduje POSIX, bude číslo větší než 128. POSIX nespecifikuje, jaká hodnota může být. V praxi však ve všech shellech podobných Bourneovi, které znám, nejnižších 7 bitů $? bude obsahovat číslo signálu. Ale kde n je číslo signálu,

  • v ash, zsh, pdksh, bash, Bourne shell, $? je 128 + n . Co to znamená, že v těchto shellech, pokud dostanete $? z 129 , nevíte, zda je to tím, že proces skončil s exit(129) nebo zda byl zabit signálem 1 (HUP na většině systémů). Důvodem však je, že když se shelly samy ukončí, ve výchozím nastavení vrátí stav ukončení posledního ukončeného příkazu. Ujistěte se, že $? není nikdy větší než 255, což umožňuje mít konzistentní stav ukončení:

    $ bash -c 'sh -c "kill $$"; printf "%xn" "$?"'
    bash: line 1: 16720 Terminated              sh -c "kill $$"
    8f # 128 + 15
    $ bash -c 'sh -c "kill $$"; exit'; printf '%xn' "$?"
    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 , $? je 256 + n . To znamená, že z hodnoty $? můžete rozlišovat mezi zabitým a neukončeným procesem. Novější verze ksh , při ukončení, pokud $? byl větší než 255, zabije se stejným signálem, aby mohl nahlásit stejný stav ukončení svému nadřazenému. I když to zní jako dobrý nápad, znamená to, že ksh vygeneruje další výpis jádra (potenciálně přepíše druhý), pokud byl proces zabit signálem generujícím jádro:

    $ ksh -c 'sh -c "kill $$"; printf "%xn" "$?"'
    ksh: 16828: Terminated
    10f # 256 + 15
    $ ksh -c 'sh -c "kill -ILL $$"; exit'; printf '%xn' "$?"
    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.
    

    Tam, kde byste dokonce mohli říci, že existuje chyba, je ksh93 zabije se, i když $? pochází z return 257 provedená funkcí:

    $ 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 . yash nabízí kompromis. Vrátí 256 + 128 + n . To znamená, že můžeme také rozlišovat mezi zabitým procesem a procesem, který byl ukončen správně. A při ukončení ohlásí 128 + n aniž byste museli spáchat sebevraždu a vedlejší účinky, které to může mít.

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

Chcete-li získat signál z hodnoty $? , přenosný způsob je použít kill -l :

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

(kvůli přenositelnosti byste nikdy neměli používat čísla signálů, pouze názvy signálů)

Související:Zálohy na úrovni bajtů versus zálohy na úrovni souborů?

Na frontách mimo Bourne:

  • csh /tcsh a fish stejný jako Bourne shell kromě toho, že stav je v $status místo $? (všimněte si, že zsh také nastaví $status kvůli kompatibilitě s csh (kromě $? )).
  • rc :stav ukončení je v $status také, ale když je zabit signálem, tato proměnná obsahuje název signálu (jako sigterm nebo sigill+core pokud bylo vygenerováno jádro) místo čísla, což je dalším důkazem dobrého návrhu tohoto shellu.
  • es . výstupní stav není proměnná. Pokud vám na tom záleží, spusťte příkaz jako:

    status = <={cmd}
    

    což vrátí číslo nebo sigterm nebo sigsegv+core jako v rc .

Možná bychom pro úplnost měli zmínit zsh 's $pipestatus a bash 's $PIPESTATUS pole, která obsahují stav ukončení komponent posledního potrubí.

A také pro úplnost, pokud jde o funkce shellu a zdrojové soubory, ve výchozím nastavení se funkce vracejí se stavem ukončení posledního spuštění příkazu, ale mohou také nastavit návratový stav explicitně pomocí return vestavěný. A zde vidíme určité rozdíly:

  • bash a mksh (od R41, regrese^Wchange zjevně zavedená záměrně) zkrátí číslo (kladné nebo záporné) na 8 bitů. Například return 1234 nastaví $? na 210 , return -- -1 nastaví $? na 255.
  • zsh a pdksh (a deriváty jiné než mksh ) povolit libovolné 32bitové dekadické celé číslo se znaménkem (-2 až 2-1) (a zkrátit číslo na 32 bitů).
  • ash a yash povolit libovolné kladné celé číslo od 0 do 2-1 a vrátit chybu pro jakékoli z nich.
  • ksh93 pro return 0 return 320 nastavit $? jak je, ale pro cokoliv jiného, ​​zkrátit na 8 bitů. Pozor, jak již bylo zmíněno, vrácení čísla mezi 256 a 320 může způsobit ksh zabít se při odchodu.
  • rc a es umožňují vrátit cokoli, dokonce i seznamy.
Související:arduino – Vyžaduje gcode kód odpovědi od interpreta?

Všimněte si také, že některé shelly také používají speciální hodnoty $? /$status hlásit některé chybové stavy, které nejsou stavem ukončení procesu, například 127 nebo 126 pro příkaz nenalezen nebo nespustitelný (nebo chyba syntaxe ve zdrojovém souboru)…


Linux
  1. Jak vyhledat výstupní kódy pro aplikace?

  2. Proč je výchozí vidlice mechanismu vytváření procesu?

  3. Jaký je ukončovací kód programu, když selžeasses()?

  1. Může exit() selhat při ukončení procesu?

  2. Bash Prompt s posledním výstupním kódem

  3. Co se stane, když se vlákno rozvětvuje?

  1. Návratový kód grep pro Linux

  2. Co dělat, když Ctrl + C nemůže zabít proces?

  3. Kdy bych neměl zabít -9 proces?