Kiedy proces zostanie zabity sygnałem nadającym się do obsługi, takim jak SIGINT
lub, SIGTERM
ale nie obsługuje on sygnału, jaki będzie kod zakończenia procesu?
Co z takimi nieobsługiwanymi sygnałami SIGKILL
?
Z tego, co mogę powiedzieć, zabicie procesu z SIGINT
prawdopodobnym wynikiem w kodzie wyjścia 130
, ale czy różni się to w zależności od implementacji jądra lub powłoki?
$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130
Nie jestem pewien, jak bym przetestował inne sygnały ...
$ ./myScript &
$ killall myScript
$ echo $?
0 # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0 # same problem
kill
signals
exit
exit-status
Cory Klein
źródło
źródło
killall myScript
prace, stąd zwrócenie killall (a nie skryptu!) wynosi 0. Możesz umieścićkill -x $$
[x będący liczbą sygnału, a $$ zwykle rozszerzane przez powłokę do PID tego skryptu (działa w sh, bash, ...)] w skrypcie, a następnie przetestuj, jaki był jego rdzeń wyjściowy.&
). Wyślij sygnał z innego procesu powłoki (w innym terminalu), a następnie możesz go użyć$?
po zakończeniu działania myScript.Odpowiedzi:
Procesy mogą wywoływać wywołanie
_exit()
systemowe (w systemie Linux, patrz takżeexit_group()
) z argumentem liczby całkowitej, aby zgłosić kod wyjścia do ich rodzica. Chociaż jest to liczba całkowita, tylko 8 najmniej znaczących bitów jest dostępnych dla rodzica (wyjątek stanowi to podczas używaniawaitid()
lub obsługi SIGCHLD w rodzicu w celu pobrania tego kodu , choć nie w Linuksie).Rodzic zwykle robi a
wait()
lub,waitpid()
aby uzyskać status swojego dziecka jako liczbę całkowitą (chociażwaitid()
można użyć również nieco innej semantyki).W systemie Linux i większości Uniksów, jeśli proces zakończy się normalnie, bity od 8 do 15 tego numeru statusu będą zawierały kod wyjścia, który został przekazany
exit()
. Jeśli nie, to 7 najmniej znaczących bitów (od 0 do 6) będzie zawierało numer sygnału, a bit 7 zostanie ustawiony, jeśli rdzeń został zrzucony.perl
jest$?
, na przykład, że zawiera szereg określonych przezwaitpid()
:Powłoki podobne do Bourne'a również ustawiają status wyjścia ostatniego polecenia uruchomienia we własnej
$?
zmiennej. Jednak nie zawiera bezpośrednio liczby zwróconej przezwaitpid()
, ale transformację i różni się między powłokami.Wspólne dla wszystkich powłok jest to, że
$?
zawiera najmniej 8 bitów kodu wyjścia (liczby przekazanej doexit()
), jeśli proces zakończy się normalnie.Różni się to, gdy proces kończy się sygnałem. We wszystkich przypadkach, a jest to wymagane przez POSIX, liczba będzie większa niż 128. POSIX nie określa, jaka może być wartość. W praktyce jednak we wszystkich znanych mi powłokach Bourne'a 7 najniższych bitów
$?
będzie zawierało liczbę sygnałów. Ale gdzien
jest numer sygnału,w ash, zsh, pdksh, bash, powłoka Bourne'a
$?
jest128 + n
. Co to znaczy, że w tych pocisków, jeśli masz$?
z129
, nie wiem, czy to dlatego, że proces zakończył działanieexit(129)
, czy też został zabity sygnałem1
(HUP
w większości systemów). Ale uzasadnieniem jest to, że powłoki, gdy same się kończą, domyślnie zwracają status wyjścia ostatnio zakończonej komendy. Upewniając się, że$?
nigdy nie jest większy niż 255, pozwala to uzyskać spójny status wyjścia:ksh93
,$?
jest256 + n
. Oznacza to, że od wartości$?
możesz rozróżnić proces zabity i nie zabity. Nowsze wersjeksh
, przy wyjściu, jeśli$?
były większe niż 255, zabijają się tym samym sygnałem, aby móc zgłosić ten sam status wyjścia rodzicowi. Chociaż wydaje się to dobrym pomysłem, oznacza to, żeksh
wygeneruje dodatkowy zrzut rdzenia (potencjalnie nadpisujący drugi), jeśli proces zostanie zabity przez sygnał generujący rdzeń:Można nawet powiedzieć, że jest błąd, który
ksh93
zabija się, nawet jeśli$?
pochodzi od funkcjireturn 257
wykonanej przez:yash
.yash
oferuje kompromis. Powraca256 + 128 + n
. Oznacza to, że możemy również odróżnić zabity proces od tego, który zakończył się prawidłowo. A po wyjściu zgłosi się128 + n
bez samobójstwa i skutków ubocznych, jakie może mieć.Aby uzyskać sygnał z wartości
$?
, przenośnym sposobem jest użyciekill -l
:(ze względu na przenośność nigdy nie należy używać numerów sygnałów, a jedynie nazw sygnałów)
Na frontach innych niż Bourne:
csh
/tcsh
i tofish
samo co powłoka Bourne'a, z tym wyjątkiem, że status jest$status
zamiast$?
(należy pamiętać, żezsh
ustawia się również$status
dla zgodności zcsh
(oprócz$?
)).rc
: status wyjścia$status
również jest, ale gdy zabije go sygnał, zmienna ta zawiera nazwę sygnału (jaksigterm
lubsigill+core
jeśli rdzeń został wygenerowany) zamiast liczby, co jest kolejnym dowodem dobrego projektu tej powłoki .es
. status wyjścia nie jest zmienną. Jeśli zależy Ci na tym, uruchom polecenie jako:która zwróci liczbę
sigterm
lubsigsegv+core
jak wrc
.Może pod względem kompletności, powinniśmy wspomnieć
zsh
„s$pipestatus
ibash
” s$PIPESTATUS
tablice, które zawierają kod zakończenia elementów ostatniej rurociągu.A także dla kompletności, jeśli chodzi o funkcje powłoki i pliki źródłowe, domyślnie funkcje zwracają ze statusem zakończenia ostatniego uruchomienia polecenia, ale mogą również ustawić jawnie status powrotu za pomocą
return
wbudowanego. Widzimy tutaj pewne różnice:bash
imksh
(od R41 regresja ^ Witch najwyraźniej wprowadzona umyślnie ) skróci liczbę (dodatnią lub ujemną) do 8 bitów. Na przykładreturn 1234
ustawimy$?
na210
,return -- -1
ustawimy$?
na 255.zsh
orazpdksh
(i pochodne inne niżmksh
) pozwalają na każdą 32-bitową liczbę całkowitą ze znakiem (-2 31 do 2 31 -1) (i skracają liczbę do 32 bitów ).ash
iyash
zezwól na dowolną liczbę całkowitą dodatnią od 0 do 2 31 -1 i zwróć błąd dla dowolnej liczby z tego.ksh93
wreturn 0
celureturn 320
ustawienia$?
w takim stanie, ale nic innego, obcina do 8 bitów. Uważaj, jak już wspomniano, że zwrócenie liczby między 256 a 320 może spowodowaćksh
samobójstwo przy wyjściu.rc
ies
zezwalaj na zwracanie dowolnych nawet listNależy również pamiętać, że niektóre powłoki również użyć specjalnych wartości
$?
/$status
zgłosić pewne warunki błędów, które nie są kod zakończenia procesu, jak127
i126
na polecenie nie znaleziono lub nie wykonywalny (lub błąd składni w pliku) pochodzących ...źródło
an exit code to their parent
ato get the *status* of their child
. podkreśliłeś „status”. Czyexit code
i*status*
to samo? Przypadek tak, skąd biorą się dwa nazwiska? Sprawa inna niż ta, czy możesz podać definicję / odniesienie statusu?exit()
. Status wyjścia : liczby otrzymanej przezwaitpid()
który zawiera kod, numer wyjście sygnału i czy istnieje rdzeń dumpingowych. Liczba udostępniana przez niektóre powłoki w jednej ze specjalnych zmiennych ($?
,$status
), która jest transformacją statusu wyjścia w taki sposób, że zawiera kod wyjścia w przypadku normalnego zakończenia, ale także przenosi informację o sygnale, jeśli proces został zabity (ten jest również ogólnie nazywany statusem wyjścia ). Wszystko to wyjaśniono w mojej odpowiedzi.> 128
część: „Status wyjścia polecenia, które zakończyło się, ponieważ otrzymał sygnał, będzie zgłaszane jako większe niż 128”. pubs.opengroup.org/onlinepubs/9699919799/utilities/…[email protected]
(od 2015-05-06) lubXref: news.gmane.org gmane.comp.standards.posix.austin.general:10726
Kiedy proces kończy działanie, zwraca wartość całkowitą do systemu operacyjnego. W większości wariantów unixa ta wartość jest pobierana modulo 256: wszystko oprócz bitów niskiego rzędu jest ignorowane. Status procesu potomnego jest zwracany do jego rodzica przez 16-bitową liczbę całkowitą, w której
Status jest zwracany przez
wait
wywołanie systemowe lub jedno z jego rodzeństwa. POSIX nie określa dokładnego kodowania statusu wyjścia i numeru sygnału; zapewnia tylkoŚciśle mówiąc, nie ma wyjścia Kod gdy proces zostaje zabity przez sygnał: co tam jest wyjście zamiast statusu .
W skrypcie powłoki status wyjścia polecenia jest zgłaszany przez specjalną zmienną
$?
. Ta zmienna koduje status wyjścia w niejednoznaczny sposób:$?
oznacza to jego status zakończenia.$?
w większości systemów jest to 128 plus numer sygnału. POSIX upoważnia tylko$?
w tym przypadku więcej niż 128; ksh93 dodaje 256 zamiast 128. Nigdy nie widziałem wariantu uniksowego, który zrobiłby coś innego niż dodanie stałej do liczby sygnału.Dlatego w skrypcie powłoki nie można jednoznacznie stwierdzić, czy polecenie zostało zabite sygnałem, czy zakończyło się kodem stanu większym niż 128, z wyjątkiem ksh93. Bardzo rzadko programy wychodzą z kodami stanu większymi niż 128, częściowo dlatego, że programiści unikają tego z powodu
$?
niejasności.SIGINT jest sygnałem 2 w większości wariantów unixa, więc
$?
wynosi 128 + 2 = 130 dla procesu, który został zabity przez SIGINT. Zobaczysz 129 dla SIGHUP, 137 dla SIGKILL itp.źródło
$?
to tylko pocisków podobnych do Bourne'a. Zobacz takżeyash
inne (ale wciąż POSIX) zachowanie. Również zgodnie z POSIX + XSI (Unix), akill -2 "$pid"
wyśle SIGINT do procesu, ale rzeczywisty numer sygnału może nie wynosić 2, więc $? niekoniecznie będzie to 128 + 2 (lub 256 + 2 lub 384 + 2), alekill -l "$?"
wróciINT
, dlatego radziłbym, aby przenośność nie odnosiła się do samych liczb.To zależy od twojej powłoki. Ze strony podręcznika
bash(1)
, sekcja SHELL GRAMMAR , podsekcja Proste polecenia :Ponieważ
SIGINT
w systemie znajduje się sygnał numer 2, zwracana wartość wynosi 130, gdy jest uruchamiany w trybie Bash.źródło
signal(7)
man.Wydaje się, że jest to właściwe miejsce, aby wspomnieć, że SVr4 wprowadził waitid () w 1989 r., Ale jak dotąd żaden ważny program nie korzysta z niego. waitid () pozwala odzyskać pełne 32 bity z kodu exit ().
Około 2 miesiące temu przepisałem część oczekiwania / kontroli zadania powłoki Bourne Shell, aby użyć waitid () zamiast waitpid (). Dokonano tego w celu usunięcia ograniczenia, które maskuje kod wyjścia za pomocą 0xFF.
Interfejs waitid () jest znacznie bardziej przejrzysty niż poprzednie implementacje wait (), z wyjątkiem wywołania cwait () z UNOS z 1980 roku.
Możesz być zainteresowany przeczytaniem strony podręcznika:
http://schillix.sourceforge.net/man/man1/bosh.1.html
i sprawdź sekcję „Zastępowanie parametrów”, która aktualnie gapi się na str. 8.
Nowe zmienne .sh. * Zostały wprowadzone dla interfejsu waitid (). Ten interfejs nie ma już dwuznacznego znaczenia dla liczb znanych z $? i znacznie ułatwi interfejs.
Pamiętaj, że musisz mieć funkcję waitid () zgodną z POSIX, aby móc korzystać z tej funkcji, więc Mac OS X i Linux obecnie tego nie oferują, ale funkcja waitid () jest emulowana w wywołaniu waitpid (), więc W przypadku platformy innej niż POSIX nadal otrzymasz tylko 8 bitów z kodu wyjściowego.
W skrócie: .sh.status to numeryczny kod wyjścia, .sh.code to numeryczny powód wyjścia.
Dla lepszej przenośności istnieje: .sh.codename dla tekstowej wersji przyczyny wyjścia, np. „DUMPED” i .sh.termsig, nazwa pojedyncza sygnału, który zakończył proces.
Dla lepszego wykorzystania istnieją dwie niezwiązane z wyjściem wartości .sh.codename: „NOEXEC” i „NOTFOUND”, które są używane, gdy program w ogóle nie może zostać uruchomiony.
FreeBSD naprawił błąd kerlnel waitid () w ciągu 20 godzin po moim raporcie, Linux nie zaczął jeszcze z naprawą. Mam nadzieję, że 26 lat po wprowadzeniu tej funkcji, która jest teraz w POSIX, wszystkie systemy operacyjne wkrótce ją obsługują.
źródło