プロセスの終了時にデフォルトの終了コードは何ですか?

プロセスの終了時にデフォルトの終了コードは何ですか?

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

答え1

プロセスは、整数引数を使用して_exit()システム呼び出し(Linuxの場合はリソースを参照)を呼び出して、親プロセスexit_group()に終了コードを報告できます。整数ですが、最下位ビット 8 個だけが上位ビットに使用できます (例外は次のとおり)。waitid()そのコードを検索するには、親でSIGCHLDまたはハンドラを使用します。、Linuxではそうではありませんが)。

親は通常、次のことを実行または取得wait()waitpid()ます。状態それらの子は整数で表されます(わずかにwaitid()異なる意味を使用することもできます)。

Linux およびほとんどの Unices でプロセスが正常に終了した場合、プロセスのビット 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 シェルで$?yes これは、これらのシェルから of を128 + n取得すると、プロセスが終了したか、シグナルによって終了したかどうかがわからないことを意味します (ほとんどのシステムでは)。 。ただし、基本原則は、シェルが独自に終了したときにデフォルトで最後の終了コマンドの終了状態を返すことです。一貫した終了状態は、255より大きくないことを保証することによって達成されます。$?129exit(129)1HUP$?

    $ 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
    
  • yashyash妥協が提案されます。それが返されます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/ステータスがinであることを除いて、Bourneシェルとtcsh同じです。 ((ext)との互換性も設定されています.)fish$status$?zsh$statuscsh$?

  • rc:シャットダウン状態も同様ですが、シグナルによってシャットダウンされると、変数には数字の代わりにシグナル$status名(sigtermコアが生成された場合など)が含まれます。これはこのシェルの良いデザインのもう1つの証拠です。sigill+core

  • es。終了状態は変数ではありません。興味がある場合は、次のコマンドを実行してください。

     status = <={cmd}
    

数字などsigtermsigsegv+core返しますrc

おそらく完全性のために、最後のパイプラインコンポーネントの終了ステータスを含むzsh's$pipestatusbash' の配列に言及する必要があります。$PIPESTATUS

そして完全にするために、シェル関数とソースファイルの場合、デフォルトでは関数は最後のコマンド実行の終了状態を返しますが、戻り状態は組み込み関数を使用して明示的に設定することもできますreturn。これにはいくつかの違いがあります。

  • bashそしてmksh(R41以降、回帰変化は明らかに意図的に導入された。)は数字(正または負)を8桁に切り捨てます。たとえば、255return 1234に設定されます。$?210return -- -1$?
  • zshそしてpdksh(そしてExceptの派生)、符号付き32ビット10進mksh整数(-2 31〜2 31 -1)を受け入れます(そして数字を32ビットに切り捨てます)。
  • ash0 と 2 31yash -1 の間の正の整数を受け入れ、その中のすべての数値に対してエラーを返します。
  • ksh93return 0あるまま設定し、return 320他の場合は8ビットに切ります。$?前述のように、256から320の数字を返すと、ksh終了時に自殺が発生する可能性があります。
  • rcリストも含めてes何でも返すことができます。

また、一部のシェルは特殊値$?/を使用して、プロセス終了状態では$statusなくいくつかのエラー状態を報告します。127126命令が見つかりませんまたは施行不可能(またはソースファイルの構文エラー)...

答え2

プロセスが終了すると、オペレーティングシステムに整数値を返します。ほとんどのUnixバリアントでは、この値はモジュロ256です。つまり、低ビットを除くすべてのビットは無視されます。子プロセスの状態は、16ビット整数を介して親プロセスに返されます。

  • ビット0〜6(下位7ビット)は、プロセスを終了するために使用される信号番号です。プロセスが正常に終了すると0になります。
  • プロセスが信号によって終了し、コアをダンプする場合、ビット7がセットされます。
  • プロセスが正常に終了すると、ビット8~15はプロセスの終了コードであり、プロセスが信号によって終了するとゼロである。

返された状態waitシステムコールまたはその兄弟のいずれかです。 POSIX は、終了ステータスとシグナル番号の正確なエンコーディングを指定しません。

  • 退室状態が信号に対応するのか、正常退出に該当するのかを判断する方法。
  • プロセスが正常に終了すると、終了コードにアクセスできます。
  • プロセスがシグナルによって終了した場合にシグナル番号にアクセスする方法。

厳密に言えば出口はないパスワード信号によってプロセスが終了すると、存在するのは終了です。状態

シェルスクリプトではコマンドの終了ステータス特殊変数による報告$?。この変数は終了状態をあいまいな方法でエンコードします。

  • プロセスが正常に終了した場合は$?終了状態です。
  • プロセスがシグナルによって終了した場合、これは$?ほとんどのシステムで128にシグナル番号を加えた値です。この場合、POSIXでは$?128より大きい数字だけが必要です。 ksh93は128の代わりに256を追加します。私は、シグナル番号に定数を追加する以外の操作を実行するUNIXのバリエーションを見たことがありません。

したがって、シェルスクリプトでは、ksh93 を除いて、コマンドがシグナルで終了したか、128 より大きいステータスコードで終了したかを確認することはできません。プログラムが128より大きいステータスコードで終了することは非常にまれです。部分的には、プログラマがあいまい$?さのために終了するのを避けるためです。

ほとんどのUnixバリアントでは、SIGINTはシグナル2なので、$?SIGINTによって終了されたプロセスの場合、SIGINTは128 + 2 = 130です。 SIGHUPは129、SIGKILLは137などで表されます。

答え3

それはシェルによって異なります。bash(1)マニュアルページから、シェル文法部分、簡単なコマンド部分:

aの戻り値簡単なコマンド[...] 128+ですNコマンドが信号によって終了する場合N

SIGINTシステムのシグナル番号は2なので、Bashで実行したときの戻り値は130です。

答え4

SVr4が1989年にwaitid()を導入したと言及するのが適切なようですが、これまで使用する重要なプログラムはないようです。 waitid()を使用すると、32ビット全体を終了()コードから取得できます。

約2ヶ月前に、私はwaitpid()の代わりにwaitid()を使用するようにBourne Shellの待機/作業制御部分を書き直しました。これは、0xFFで終了コードをマスクする制限を排除するために行われます。

waitid() インタフェースは、1980 年の UNOS の cwait() 呼び出しを除いて、以前の wait() 実装よりはるかに簡単です。

次のマニュアルページを読むことに興味があるかもしれません。

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

そして、8ページから始まる現在の「パラメータの置き換え」セクションを確認してください。

waitid() インタフェースに新しい変数 .sh.* が導入されました。このインタフェースは、$? で知られている数字に対してあいまいな意味を持ちません。インターフェイスが簡単になります。

この機能を使用するにはPOSIX互換のwaitid()が必要なため、Mac OSの終了コードから8ビットしか取得できません。

つまり、.sh.statusは数値終了コードで、.sh.codeは数値終了の理由です。

より移植性のために、「DUMPED」などの終了理由のテキストバージョンを表す.sh.codenameと、プロセスを終了した信号の信号名を示す.sh.termsigがあります。

より良い使用のためにプログラムをまったく起動できないときに使用される「NOEXEC」と「NOTFOUND」という2つの終了独立した.sh.codename値があります。

FreeBSDは私が報告してから20時間以内にwaitid()カーネルのバグを修正しましたが、Linuxではまだ修正を開始していません。この機能がPOSIXに導入されてから26年が経過すると、すべてのオペレーティングシステムがまもなくそれを正しくサポートできることを願っています。

関連情報