[解決済み】bashで不要な遅延を発生させずにコマンドをタイムアウトさせる
質問
この回答 から 一定時間後にコマンドを自動終了させるコマンドラインコマンド
は、bash のコマンドラインから長時間実行するコマンドをタイムアウトさせる 1 行のメソッドを提案しています。
( /path/to/slow command with options ) & sleep 5 ; kill $!
しかし、与えられた "long-running"コマンドがタイムアウトより早く終了する可能性があります。
(このコマンドを、quot;typically-long-running but-sometimes-fast" と呼ぶことにします。
tlrbsf
を、お楽しみに)
この気の利いた1ライナーのアプローチには、いくつかの問題があるわけです。
まず
sleep
は条件付きではないので、シーケンスが終了するまでにかかる時間に望ましくない下限が設定されます。30秒とか2mとか5mとかのスリープを考えてみてください。
tlrbsf
コマンドは2秒で終了するため、非常に好ましくありません。
次に
kill
は無条件なので、このシーケンスは実行されていないプロセスを kill しようとし、それについて泣き言を言うでしょう。
それで...
方法はありますか? をタイムアウトさせるには、通常長く実行されるが時々速い ( "tlrbsf" というコマンドを実行します。
- はbashの実装があります(他の質問にはすでにPerlとCの回答があります)。
- はどちらか早い方で終了します。 tlrbsf プログラムの終了、またはタイムアウトの経過
- は、存在しない、あるいは実行されていないプロセスを kill しない(あるいは、オプションで 文句を言う を実行します。)
- 1ライナーである必要はない
- CygwinまたはLinuxで実行可能
...そして、ボーナスポイントとして
- が実行されます。 tlrbsf コマンドをフォアグラウンドで実行します。
- バックグラウンドの 'スリープ' または余分なプロセス
のstdin/stdout/stderrが、そのような tlrbsf コマンドを直接実行した場合と同じように、リダイレクトすることができますか?
もしそうなら、あなたのコードを共有してください。そうでない場合は、その理由を説明してください。
前述の例をハックするのにしばらく費やしましたが、私のbashスキルの限界にぶつかっています。
どのように解決するのですか?
まさにご指摘の通りだと思います。
http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
#!/bin/bash
#
# The Bash shell script executes a command with a time-out.
# Upon time-out expiration SIGTERM (15) is sent to the process. If the signal
# is blocked, then the subsequent SIGKILL (9) terminates it.
#
# Based on the Bash documentation example.
# Hello Chet,
# please find attached a "little easier" :-) to comprehend
# time-out example. If you find it suitable, feel free to include
# anywhere: the very same logic as in the original examples/scripts, a
# little more transparent implementation to my taste.
#
# Dmitry V Golovashkin <[email protected]>
scriptName="${0##*/}"
declare -i DEFAULT_TIMEOUT=9
declare -i DEFAULT_INTERVAL=1
declare -i DEFAULT_DELAY=1
# Timeout.
declare -i timeout=DEFAULT_TIMEOUT
# Interval between checks if the process is still alive.
declare -i interval=DEFAULT_INTERVAL
# Delay between posting the SIGTERM signal and destroying the process by SIGKILL.
declare -i delay=DEFAULT_DELAY
function printUsage() {
cat <<EOF
Synopsis
$scriptName [-t timeout] [-i interval] [-d delay] command
Execute a command with a time-out.
Upon time-out expiration SIGTERM (15) is sent to the process. If SIGTERM
signal is blocked, then the subsequent SIGKILL (9) terminates it.
-t timeout
Number of seconds to wait for command completion.
Default value: $DEFAULT_TIMEOUT seconds.
-i interval
Interval between checks if the process is still alive.
Positive integer, default value: $DEFAULT_INTERVAL seconds.
-d delay
Delay between posting the SIGTERM signal and destroying the
process by SIGKILL. Default value: $DEFAULT_DELAY seconds.
As of today, Bash does not support floating point arithmetic (sleep does),
therefore all delay/time values must be integers.
EOF
}
# Options.
while getopts ":t:i:d:" option; do
case "$option" in
t) timeout=$OPTARG ;;
i) interval=$OPTARG ;;
d) delay=$OPTARG ;;
*) printUsage; exit 1 ;;
esac
done
shift $((OPTIND - 1))
# $# should be at least 1 (the command to execute), however it may be strictly
# greater than 1 if the command itself has options.
if (($# == 0 || interval <= 0)); then
printUsage
exit 1
fi
# kill -0 pid Exit code indicates if a signal may be sent to $pid process.
(
((t = timeout))
while ((t > 0)); do
sleep $interval
kill -0 $$ || exit 0
((t -= interval))
done
# Be nice, post SIGTERM first.
# The 'exit 0' below will be executed if any preceeding command fails.
kill -s SIGTERM $$ && kill -0 $$ || exit 0
sleep $delay
kill -s SIGKILL $$
) 2> /dev/null &
exec "$@"
関連
-
[解決済み] Bashスクリプトのソースディレクトリをスクリプト自体から取得するにはどうすればよいですか?
-
[解決済み] Bashシェルスクリプトでディレクトリが存在するかどうかを確認するにはどうすればよいですか?
-
[解決済み] Bashで通常のファイルが存在しないかどうかを判断する方法を教えてください。
-
[解決済み] Bashで文字列変数を連結する方法
-
[解決済み] Bash prints リテラルの改行をエコーする \n
-
[解決済み] Bashスクリプトからプログラムが存在するかどうかを確認するにはどうすればよいですか?
-
[解決済み] Windowsのコマンドラインに'which'に相当するものはありますか?
-
[解決済み] Bashでコマンドライン引数を解析するには?
-
[解決済み] Bashでコマンドの出力に変数を設定するにはどうすればよいですか?
-
[解決済み】Bashでファイル名と拡張子を抽出する。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】firebase-tools "-bash: firebase: command not found".
-
[解決済み] '\r': command not found - .bashrc / .bash_profile [duplicate].
-
[解決済み] Bashで文字列から改行を削除する方法
-
[解決済み] bash スクリプトの "${BASH_SOURCE[0]}" と $( cd $( dirname "xxx" && pwd )) の意味について
-
[解決済み] configureコマンドが見つからない cygwin
-
[解決済み] bash スクリプトを実行しているドッカーエントリーポイントが "パーミッション拒否" になる
-
[解決済み] docker alpine /bin/sh script.sh not found
-
[解決済み] パイプと二重パイプのどちらの OR 演算子を使うか?
-
npm err インストールエラーの解決策
-
[解決済み] Grep 'binary file matches'. どうすれば正常なgrepの出力が得られるか?[重複]する