GNU/Linux >> Linux の 問題 >  >> Linux

シェルスクリプトでタイムアウトしますか?

シェルスクリプトがあります それは標準入力からの読み取りです 。まれな状況では、入力を提供する準備ができている人がいないため、スクリプトはタイムアウトする必要があります 。タイムアウトの場合、スクリプトはクリーンアップコードを実行する必要があります。それを行うための最良の方法は何ですか?

このスクリプトは非常に移植性が高い必要があります 、Cコンパイラのない20世紀のUNIXシステムやbusyboxを実行している組み込みデバイスを含むため、Perl、bash、コンパイルされた言語、さらには完全なPOSIX.2にさえ依存できません。特に、$PPIDread -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; }'`



Linux
  1. ソースシェルスクリプトへのパスを決定しますか?

  2. シェルスクリプトの予期しない動作?

  3. シェルスクリプトで一時ファイルを作成するにはどうすればよいですか?

  1. シェルスクリプトでパスワードを隠す?

  2. $の意味は?シェルスクリプトでは?

  3. 星のピラミッドを出力するシェルスクリプト

  1. Linux シェルの音訳スクリプト

  2. 実行時にスクリプトでシェルを決定する

  3. 別のユーザーとしてシェル スクリプトを実行する