HOWTO · Bash

Bash シェルスクリプトを X 秒間一時停止する

Bash の sleep と read を使って、スクリプトを時間指定または入力待ちで一時停止する方法を解説します。

このページの内容

Bash スクリプトは、メッセージを読む時間を設けたり、対話的な入力を待ったり、コマンドの間に間隔を空けたりできます。秒単位で待つには sleep を、入力があるまで待つには read を使います。これらはスクリプトを続行するタイミングを制御する方法です。単に時間を空けても、共有ファイルへのアクセス順序は調整できません。

Bash スクリプトを X 秒間一時停止する

次のコマンドを遅らせるには、秒数を整数で指定して sleep を実行します。時間の指定は必須です。sleep のマニュアルでコマンドの説明を確認できます。小数の秒数や時間単位の接尾辞を使えるかどうかは、システムにインストールされている sleep の実装によって異なります。

次の Bash スクリプトはメッセージを表示し、1 秒の待機を要求してから、もう一つのメッセージを表示します。

#!/usr/bin/env bash
printf '%s\n' 'The script is starting.'
sleep 1
printf '%s\n' 'One second wait requested.'

指定した時間は目安であり、実際の経過時間がぴったり一致する保証はありません。システムのスケジューリングによって、待ち時間が長くなることがあります。処理を一定間隔で繰り返すには、処理と sleep をループに入れます。繰り返すたびに何が起きるのか明確になるよう、ループ内の処理を絞ってください。

Bash スクリプトを可変の時間だけ一時停止する

秒単位の待ち時間を変数に格納し、sleep に渡すときは変数展開を引用符で囲みます。次のスクリプトは既定で 5 秒待ちます。環境変数 N を設定すれば、別の値を指定できます。

#!/usr/bin/env bash
N=${N:-5}
sleep "$N"
printf 'Requested a %s-second wait.\n' "$N"

たとえば N=8 ./your-script.sh と実行すると、その呼び出しに限って N に 8 が設定されます。値は、インストール済みの sleep コマンドが受け付ける有効な時間でなければなりません。引用符で囲むと単語分割やパス名展開を防げますが、任意の入力が有効な時間になるわけではありません。ユーザー入力や信頼できない入力を使う場合は、事前に値を検証してください。

Bash では $RANDOM を範囲内の値に変換して、秒単位の待ち時間をランダムにできます。次のスクリプトは 1 秒から 3 秒までの待機を要求します。

#!/usr/bin/env bash
delay=$((1 + RANDOM % 3))
printf 'Requested a %s-second wait.\n' "$delay"
sleep "$delay"

ランダムな待ち時間を使うと、別々に起動したスクリプトの開始時刻にばらつきを持たせられます。ただし、複数の実行が同じファイルへ同時に書き込むのを防ぐことはできません。スクリプト間でリソースを共有する場合は、適切なロックや調整の仕組みを使ってください。

ユーザー入力があるまで Bash スクリプトを一時停止する

Bash の read コマンドは、標準入力から 1 行読み取るまで待ちます。対話型の端末では、通常、ユーザーが Enter キーを押すと入力が確定します。-r を付けると入力中のバックスラッシュをそのまま扱い、-p を付けるとプロンプトを表示できます。

#!/usr/bin/env bash
if read -r -p 'Press Enter to continue: ' reply; then
    printf '%s\n' 'Continuing.'
else
    printf '%s\n' 'No input line was available.'
fi

この例は対話的な入力を想定しており、1 行が届くまで無期限に待つことがあります。標準入力がファイル終端に達していたり、別の入力元にリダイレクトされていたりすると、read は行を受け取らずに戻る場合があります。終了ステータスを確認すれば、その状況を処理できます。Bash の read に関する説明に、オプションや動作が記載されています。

時間指定の待機とユーザー入力待ちを組み合わせる

入力があれば早く続行し、一定時間内に入力がなければタイムアウト後に続行するには、Bash の read -t を使います。タイムアウトは秒単位です。システムのスケジューリングによって、実際の経過時間は指定より長くなることがあります。次の例は、どちらの出来事で処理が続行したかを表示します。

#!/usr/bin/env bash
if read -r -t 5 -p 'Continue now, or wait for the timeout: ' reply; then
    printf '%s\n' 'Input received; continuing.'
else
    printf '%s\n' 'No line was read before the wait ended; continuing.'
fi

ユーザーに秒数を指定してもらう場合は、値を変数に読み込み、引用符で囲んで sleep に渡します。次の例では、sleep を呼び出す前に短い数値かどうかを確認し、有効な行が入力されなかった場合はメッセージを表示します。

#!/usr/bin/env bash
if read -r -p 'Enter a whole number of seconds (up to 3 digits): ' duration \
    && [[ $duration =~ ^[0-9]{1,3}$ ]]; then
    sleep "$duration"
    printf 'Requested a %s-second wait.\n' "$duration"
else
    printf '%s\n' 'Enter a whole number with at most 3 digits.'
fi

この例では、値が sleep に渡る前に検証されるため、不正な文字列を時間として渡さずに済みます。異なる上限が必要なら許容範囲を調整し、その条件を利用者に伝えてください。

時間を指定して秒単位で待つには sleep、入力を待つには read を使います。Bash の read -t なら、1 行の入力が届くかタイムアウトするまで待つことができます。