プロセスがSIGINT
やSIGTERM
などの処理可能なシグナルで強制終了されたが、シグナルを処理しない場合、プロセスの終了コードは何になりますか?
SIGKILL
のような処理できないシグナルについてはどうですか?
私が知ることができることから、SIGINT
でプロセスを強制終了すると、終了コード130
になる可能性がありますが、カーネルまたはシェルの実装によって異なりますか?
$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130
他の信号をどのようにテストするかわかりません...
$ ./myScript &
$ killall myScript
$ echo $?
0 # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0 # same problem
プロセスは、整数引数を使用して_exit()
システムコール(Linuxでは、exit_group()
も参照)を呼び出して、親に終了コードを報告できます。これは整数ですが、親が使用できるのは最下位8ビットのみです(ただし、例外は 親のSIGCHLDでwaitid()
またはハンドラーを使用してそのコードを取得する場合 Linuxではありません)。
親は通常、wait()
またはwaitpid()
を実行して、子のstatusを整数(ただし、セマンティクスが多少異なるwaitid()
も使用できます)。
LinuxおよびほとんどのUnicesでは、プロセスが正常に終了した場合、そのstatus番号のビット8から15に、exit()
。そうでない場合、7つの最下位ビット(0〜6)にシグナル番号が含まれ、コアがダンプされた場合はビット7が設定されます。
たとえば、Perl
の_$?
_には、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のようなシェルも、最後の実行コマンドの終了ステータスを独自の_$?
_変数に入れます。ただし、waitpid()
によって返される数値は直接含まれていませんが、その変換が含まれており、シェル間で異なります。
すべてのシェルに共通するのは、プロセスが正常に終了した場合、_$?
_には終了コードの最下位8ビット(exit()
に渡される数)が含まれることです。
異なるのは、プロセスがシグナルによって終了した場合です。すべての場合で、それはPOSIXで必要とされ、数値は128より大きくなります。POSIXは、値が何であるかを指定しません。しかし実際には、私が知っているすべてのBourneのようなシェルでは、_$?
_の最下位7ビットにシグナル番号が含まれます。ただし、n
はシグナル番号です。
ash、zsh、pdksh、bash、Bourne Shellでは、_$?
_は_128 + n
_です。つまり、これらのシェルでは、_$?
_の_129
_を取得した場合、そのプロセスがexit(129)
で終了したためか、それによってkillされたかがわかりません。信号_1
_(ほとんどのシステムではHUP
)。しかし、その根拠は、シェルが自分自身で終了した場合、デフォルトでは最後に終了したコマンドの終了ステータスを返すということです。 _$?
_が255より大きくならないようにすることで、一貫した終了ステータスを得ることができます。
_$ 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
_、_$?
_は_256 + n
_です。つまり、_$?
_の値から、強制終了されたプロセスと強制終了されていないプロセスを区別できます。 ksh
の新しいバージョンは、終了時に、_$?
_が255より大きい場合、同じ終了ステータスを親に報告できるように、同じシグナルで自分自身を強制終了します。これは良い考えのように思えますが、これは、プロセスがコア生成シグナルによって強制終了された場合、ksh
が追加のコアダンプを生成する(他のコアダンプを上書きする可能性がある)ことを意味します。
_$ 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.
_
_ksh93
_が関数によって実行された_$?
_からのものである場合でも、_return 257
_が自分自身を殺すというバグがあると言うことさえできます:
_$ 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
は妥協案を提示します。 _256 + 128 + n
_を返します。つまり、強制終了されたプロセスと適切に終了したプロセスを区別することもできます。そして、終了すると、それ自体を自殺することなく、_128 + n
_とその副作用を報告します。
_$ 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
_
_$?
_の値から信号を取得するには、移植可能な方法は_kill -l
_を使用することです。
_$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM
_
(移植性のため、シグナル番号は使用せず、シグナル名のみを使用してください)
ボーン以外の正面:
csh
/tcsh
およびfish
ステータスが_$status
_ではなく_$?
_にあることを除いて、Bourne Shellと同じ(zsh
はcsh
との互換性のために_$status
_も設定します(_$?
_)に加えて)。rc
:終了ステータスも_$status
_にありますが、シグナルによって強制終了された場合、その変数にはシグナルの名前が含まれます(sigterm
または_sigill+core
_ ifコアが生成された)数の代わりに、これはそのシェルの優れたデザインのもう1つの証拠です。es
。終了ステータスは変数ではありません。気になる場合は、次のようにコマンドを実行します。
_status = <={cmd}
_
sigterm
のように、数値またはrc
または_sigsegv+core
_を返します。
完全を期すために、最後のパイプラインのコンポーネントの終了ステータスを含むzsh
の_$pipestatus
_およびbash
の_$PIPESTATUS
_配列について言及する必要があります。
また、完全を期すために、シェル関数とソースファイルについては、デフォルトで、関数は最後に実行されたコマンドの終了ステータスで戻りますが、return
ビルトインで明示的に戻りステータスを設定することもできます。ここにいくつかの違いがあります:
bash
およびmksh
(R41以降、 回帰^ Wchangeは明らかに意図的に導入された )は、数値(正または負)を8ビットに切り捨てます。たとえば、_return 1234
_は_$?
_を_210
_に設定し、_return -- -1
_は_$?
_を255に設定します。zsh
およびpdksh
(およびmksh
以外の導関数)は、任意の符号付き32ビット10進整数(-231 2に31-1)(および数値を32ビットに切り捨てます)。ash
およびyash
は0〜2の任意の正の整数を許可します31-1で、その中の任意の数のエラーを返します。ksh93
_ for _return 0
_ to _return 320
_は_$?
_をそのまま設定しますが、それ以外の場合は8ビットに切り捨てます。すでに述べたように、256〜320の数値を返すと、終了時にksh
が強制終了する可能性があることに注意してください。rc
およびes
を使用すると、リストも返すことができます。また、一部のシェルは_$?
_/_$status
_の特別な値を使用して、_127
_または_126
_ forコマンドが見つかりませんまたは実行可能ではありません(またはソースファイルの構文エラー) ...
プロセスが終了すると、オペレーティングシステムに整数値が返されます。ほとんどのUNIXバリアントでは、この値は256を法として取得されます。下位ビット以外はすべて無視されます。子プロセスのステータスは、16ビット整数を介して親に返されます。
ステータスは wait
システムコールまたはその兄弟のいずれかによって返されます。 POSIXは、終了ステータスとシグナル番号の正確なエンコーディングを指定していません。それは提供するだけです
厳密に言えば、プロセスがシグナルによって強制終了された場合、出口codeはありません。代わりに出口があります。ステータス。
シェルスクリプトでは、 コマンドの終了ステータス は特殊変数 $?
を介して報告されます。この変数は、あいまいな方法で終了ステータスをエンコードします。
$?
はその終了ステータスです。$?
は128にほとんどのシステムのシグナル番号を加えたものになります。この場合、POSIXは$?
が128より大きいことのみを要求します。 ksh93は128ではなく256を追加します。信号番号に定数を追加する以外のことを行うUNIXバリアントを見たことはありません。したがって、シェルスクリプトでは、ksh93を除いて、コマンドがシグナルによって強制終了されたのか、128より大きいステータスコードで終了したのかを決定的に判断することはできません。 $?
のあいまいさが原因でプログラマーがそれを回避するため、プログラムが128より大きいステータスコードで終了することは非常にまれです。
ほとんどのUNIXバリアントではSIGINTはシグナル2であるため、SIGINTによって強制終了されたプロセスの$?
は128 + 2 = 130です。 SIGHUPには129、SIGKILLには137などが表示されます。
それはあなたのシェルに依存します。 bash(1)
のマニュアルページから、Shell GRAMMARセクション、Simple Commandsサブセクション:
簡単なコマンドの戻り値は[...] 128 +nコマンドがシグナルnで終了した場合。
システムのSIGINT
はシグナル番号2であるため、Bashで実行した場合の戻り値は130です。
SVr4が1989年にwaitid()を導入したことを言及するのは正しい場所のようですが、今のところ重要なプログラムはそれを使用していないようです。 waitid()を使用すると、exit()コードから32ビット全体を取得できます。
約2か月前、Bourne Shellの待機/ジョブ制御部分を書き直して、waitpid()ではなくwaitid()を使用しました。これは、終了コードを0xFFでマスクする制限を取り除くために行われました。
Waitid()インターフェースは、1980年からのUNOSからのcwait()呼び出しを除いて、以前のwait()実装よりもはるかにクリーンです。
次の場所にあるmanページをご覧ください。
http://schillix.sourceforge.net/man/man1/bosh.1.html
そして、現在8ページにある「パラメータ置換」のセクションをチェックしてください。
新しい変数.sh。*がwaitid()インターフェースに導入されました。このインターフェイスは、$で知られている数値に対して曖昧な意味を持たなくなりました。インターフェースがはるかに簡単になります。
この機能を使用するにはPOSIX準拠のwaitid()が必要なので、Mac OS XとLinuxは現在この機能を提供していませんが、waitid()はwaitpid()呼び出しでエミュレートされるため、非POSIXプラットフォームでは、終了コードから8ビットしか取得できません。
つまり、.sh.statusは数値の終了コードであり、.sh.codeは数値の終了理由です。
移植性を高めるために、次のものが用意されています。終了理由のテキストバージョン用の.sh.codename。 "DUMPED"と.sh.termsigは、プロセスを終了させたシグナルの信号名です。
使いやすくするために、exitに関連しない2つの.sh.codename値があります。「NOEXEC」と「NOTFOUND」は、プログラムをまったく起動できないときに使用されます。
FreeBSDは私の報告から20時間以内にwaitid()カーネルバグを修正しましたが、Linuxはまだ修正を開始していませんでした。この機能をPOSIXに導入してから26年後に、すべてのOSがすぐにそれをサポートすることを願っています。