次の(G)AWKスクリプトフラグメントについて質問があります。
do {
...
} while (system("sleep 10"))
私の意図は、ユーザーがスリープ中に^ Cを押したときにループを切断することですが、うまくいきません。
問題は、少なくともAWKによって実行されたときに^ Cで中断されると、Bashが0で終了することですsystem()
。
$ awk 'BEGIN { print "\n" system("sleep 2") }'
(let the sleep complete)
0
$ awk 'BEGIN { print "\n" system("sleep 2") }'
^C
0
なぜですか?
これはBashまたは(G)AWKのバグですか?
たとえば、複雑なBash固有の構文を含まない単純な解決策はありますかtrap
?
私が考えることができる最善は次のとおりです。
do {
...
} while (42 == system("sleep 10 && exit 42"))
私にとって、それはまだ間違った砂利のように感じます。
答え1
system()
何を返すべきですか?あいまいに指定。
実装で一般的に見えるのは、awk
通常の終了時に終了コード(モジュールとして256に渡された数字exit(3)
)を返しますが、シェルプロセスが信号によって終了したときに動作が大きく異なることです。
さらに、C関数は親項目でSIGINT(およびSIGQUIT)を無視するように設計されていますが、その要件がssystem(3)
にも適用されるかどうかは(少なくとも私にとっては)明確ではありません。いくつかの実装(例:)はそのSIGINTで終了します(関数を実行しているという理由だけでCTRL-Cを無視するのが好きではないため、見たい動作でもあります)。一部(たとえば、または従来の実装)にあります。awk
system()
awk
mawk
awk
system()
gawk
さらに、一部のシェルはこれらの信号の一部を傍受して最終的に呼び出すことができ、exit()
これは動作に影響を与える可能性があります(Bourneシェルの説明の説明を参照)。これはexec
、以下の例でシェルを削除するために使用するものです。ループ理由。
SIGINTに返された値(1をsystem()
考慮するとより多くのバリアント)について、次のことがわかります。close()
$ nawk 'BEGIN {print system("exec kill -s INT $$")}'
0.0078125
$ bwk-awk 'BEGIN {print system("exec kill -s INT $$")}'
0.0078125
$ mawk 'BEGIN {print system("exec kill -s INT $$")}'
130
$ gawk 'BEGIN {print system("exec kill -s INT $$")}'
0
0.0078125
2 / 256
(コアがダンプされている場合は0.542969((128 + 11)/256)SEGV
、そうでない場合は0.0429688(11 / 256))、11
Solaris 10または11、またはLinuxポートのHeirloom Toolboxにありnawk
ますnawk
。bwk-awk
awk
Brian Kernighanが直接管理(K
中央awk
)いくつかのBSDで見つけることができる基本事項awk
(Debian GNU / Linuxでテスト済み)。/usr/xpg4/bin/awk
Solaris 11での動作はgawk
。
したがって、s
返された値system(3)
(ビット0〜6は信号番号、ビット7はコアビット、ビット8〜15は終了コードの整数)に基づいて、上記の結果は次のようにawk
返されますsystem()
。
s / 256
(伝統的なawk
実装)、int(s/256)
(gawk
)、- または、
mawk
BourneやCシェルなどのシェルが実行するのと同じ変換((s&127)+128
終了した場合、s>>8
そうでない場合)を除いて、コアがダンプされている場合の(s&127)+256
代わりに(s&127)+128
(の値(s&255)+128
)を取得します。
ここでは、次のようにすることができます。
awk 'BEGIN{print system("trap exit\\ 1 INT; sleep 10")}'
ただし、一部の実装がawk
終了する可能性があります。あなたのものまたはあなたの場合は、次のことができます。awk
mawk
sh
bash
yash
awk 'BEGIN{print system("set -m; sleep 10; exit")}'
したがって、sleep
それは独自のプロセスグループで実行されます(そしてSIGINTのみが得られます)。
別のオプションは、呼び出す前にSIGINTを無視することですawk
。ただし、ほとんどのシェル(POSIX要件)は、起動時にシグナルが無視されるとシグナルハンドラーを変更することはできません。だから、次のようになります。
(
trap '' INT
awk 'BEGIN{print system("trap exit\\ 1 INT; sleep 10; exit")}'
)
動作しません。zsh
ただし、そのような(自己発生)制限はないため、利用可能であることがわかっているzsh
場合は、次のことができます。
(
trap '' INT
awk 'BEGIN{print system("exec zsh -c \"TRAPINT() exit 1; sleep 10\"")}'
)
awk
どちらかが機能し、mawk
ジョブgawk
制御を妨げない可能性があります。ただし、この時点では、必要に応じて信号処理を調整できるperl
// python
...ruby
の代わりに使用を検討する価値があります。awk
ノート
1close()
パイプの上:
awk 'BEGIN {cmd = "kill -s INT $$"; cmd | getline; print close(cmd)}'
まず、これは私が試したすべての実装で^C
中断されます(SIGINT / SIGQUITがawk
forを無視したり、好きな要件はありません(これを実装する自然な方法))。popen(3)
pclose(3)
getline
system(3)
s
ただし、終了状態(上記のような/返された値がある場所)については、次のことがわかります。pclose(3)
waitpid(2)
system()
- Solaris
nawk
: 動作しません。close()
Solarisではそれを呼び出すことはできませんnawk
。 /usr/xpg4/bin/awk
ソラリスから。exit(1)
プロセスが完了しても常にゼロを返します。明らかに一貫性エラーです。gawk
とbwk-awk
:提供s
(exit 1
256提供、SIGINTでキル2提供、SIGSEGV 11でキル、コア提供139)。mawk
:と同じで、これを考慮した唯一の実装のようですsystem()
。mawk