シェルスクリプトがあります それは標準入力からの読み取りです 。まれな状況では、入力を提供する準備ができている人がいないため、スクリプトはタイムアウトする必要があります 。タイムアウトの場合、スクリプトはクリーンアップコードを実行する必要があります。それを行うための最良の方法は何ですか?
このスクリプトは非常に移植性が高い必要があります 、Cコンパイラのない20世紀のUNIXシステムやbusyboxを実行している組み込みデバイスを含むため、Perl、bash、コンパイルされた言語、さらには完全なPOSIX.2にさえ依存できません。特に、$PPID
、read -t
完全にPOSIX準拠のトラップは使用できません。一時ファイルへの書き込みも除外されます。すべてのファイルシステムが読み取り専用でマウントされている場合でも、スクリプトが実行される可能性があります。
物事をより難しくするために、スクリプトを適度に高速にすることも必要です。 タイムアウトしないとき。特に、forkとexecが特に低いWindows(主にCygwin)でもスクリプトを使用しているので、それらの使用を最小限に抑えたいと思います。
一言で言えば、私は
trap cleanup 1 2 3 15
foo=`cat`
タイムアウトを追加したいと思います。 cat
を置き換えることはできません read
で ビルトイン。タイムアウトの場合、cleanup
を実行したい 機能。
背景:このスクリプトは、8ビット文字を出力し、前後のカーソル位置を比較することにより、端末のエンコードを推測しています。スクリプトの最初は、stdoutがサポートされている端末に接続されていることをテストしますが、環境が横になっている場合があります(例:plink
TERM=xterm
を設定します TERM=dumb
で呼び出された場合でも )。スクリプトの関連部分は次のようになります:
text='Éé' # UTF-8; shows up as Ãé on a latin1 terminal
csi='␛['; dsr_cpr="${csi}6n"; dsr_ok="${csi}5n" # ␛ is an escape character
stty_save=`stty -g`
cleanup () { stty "$stty_save"; }
trap 'cleanup; exit 120' 0 1 2 3 15 # cleanup code
stty eol 0 eof n -echo # Input will end with `0n`
# echo-n is a function that outputs its argument without a newline
echo-n "$dsr_cpr$dsr_ok" # Ask the terminal to report the cursor position
initial_report=`tr -dc ;0123456789` # Expect ␛[42;10R␛[0n for y=42,x=10
echo-n "$text$dsr_cpr$dsr_ok"
final_report=`tr -dc ;0123456789`
cleanup
# Compute and return initial_x - final_x
tr
の場合、スクリプトを変更するにはどうすればよいですか。 2秒経っても入力を読み取らなかった場合、入力は強制終了され、スクリプトはcleanup
を実行します。 機能?
承認された回答:
これはどうですか:
foo=`{ { cat 1>&3; kill 0; } | { sleep 2; kill 0; } } 3>&1`
つまり、出力生成コマンドを実行し、sleep
同じプロセスグループ内で、それらのためだけのプロセスグループ。どちらのコマンドが最初に返されるかは、プロセスグループ全体を強制終了します。
誰もが不思議に思うでしょう:はい、パイプは使用されていません。リダイレクトを使用してバイパスされます。その唯一の目的は、シェルに同じプロセスグループ内の2つのプロセスを実行させることです。
関連:DMGディスクイメージを縮小および圧縮するスクリプトは、シナリオではうまく機能しないようですか?Gillesがコメントで指摘したように、これはシェルスクリプトでは機能しません。これは、スクリプトプロセスが2つのサブプロセスとともに強制終了されるためです。
コマンドを別のプロセスグループで強制的に実行する1つの方法¹は、新しいインタラクティブシェルを開始することです。
#!/bin/sh
foo=`sh -ic '{ cat 1>&3; kill 0; } | { sleep 2; kill 0; }' 3>&1 2>/dev/null`
[ -n "$foo" ] && echo got: "$foo" || echo timeouted
ただし、これには注意が必要な場合があります(たとえば、stdinがttyでない場合)。 stderrリダイレクトは、インタラクティブシェルが強制終了されたときに「終了」メッセージを取り除くためにあります。
zsh
でテスト済み 、bash
およびdash
。しかし、オールディーズはどうですか?
B98は、GNUbash3.2.57を使用するMacOSX、またはダッシュを使用するLinuxで動作する次の変更を提案しています。
foo=`sh -ic 'exec 3>&1 2>/dev/null; { cat 1>&3; kill 0; } | { sleep 2; kill 0; }'`
–