LoginSignup
7
3

More than 5 years have passed since last update.

timeoutをシェルスクリプトで実現する

Posted at

gnuのcoreutilsの中にtimeoutというコマンドがある。

これを使うと、「コマンドが一定時間たっても終了しない場合にkillする」という処理が実現できる。
詳しくはこちらをご覧いただきたい。
https://qiita.com/ma2saka/items/741b614418bf8fce04de

通常の環境ではcoreutilsのtimeoutを用いればよい。
ここでは「coreutilsが使えない環境でシェルスクリプトで実現したい」というマニアックな要望を叶えるための方法について記載する。

参考にした記事:

結論

こちらを.bashrcなり.zshrcなりに書けば終わり。

timeout.sh
timeout() {

    time=$1

    # start the command in a subshell to avoid problem with pipes
    # (spawn accepts one command)
    command="/bin/sh -c \"${@:2}\""

    expect -c "set timeout $time; spawn -noecho $command; expect timeout { exit 124 } eof; catch wait result; exit [lindex \$result 3]"
}

使い方

timeout 1 sleep 3    # `sleep 3`が途中でkillされて、1秒で処理が完了する。timeoutした場合の返り値は124

内容の説明

中でexpectというコマンドを使っている。expectは本来は対話式のコマンドを自動化するためのコマンド。しかしこの中にtimeoutの機能も含まれているのでそれを利用している。

expectの引数で与えるコマンドの中で set timeout {秒数} とするとタイムアウトの時間を設定できる。

spawn -noecho $command;の spawnというのは外部プロセスを起動するexpectのスクリプトの記法。ここでコマンドを起動している。

expect timeout { exit 124 } eof はパターンマッチ的な処理を行なっている。もしタイムアウトによって処理が終了した場合は、リターンコード124を返す。そうではない場合は eofの処理が行われるが、ここでは特別に何かを行なっているわけではない。

catch wait result; exit [lindex \$result 3] ここがspawnで起動したコマンドのリターンコードを取得している箇所。resultという変数に結果が入っている。resultは配列になっていて、プロセスの返り値以外の情報も入っている。lindexで返り値のみを取得する。\$resultというようにエスケープされているのは、変数名がシェルではなくexpectコマンドによって解釈されるようにするため。

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3