BASHシェルスクリプトで「キー入力待ち」プロンプトを実装する

2017.06.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

BASHシェルスクリプト実行中に、
例えば下記のように表示させたい場面はよくあります。

実行しますか? (y or N):

ここで人間が「y(あるいはYes)」と入力しないと先に進まない、問題があればNと入力して終了したり、CTRL+Cで強制終了させたり。
そんなプロンプト機能を実装してみます。

先にネタばらしをすると、全部readコマンドがやってくれます。

例1 : 「Hit enter key!」

単に実行を一時停止して、問題がなければエンター(リターン)キーを押すことで先に進むようなシェルスクリプトは、このようになります。

#!/bin/bash
  :
(前段階の処理)

read -p "Hit enter: "

(続きの処理)
  :

単に「Hit enter: 」と表示して処理が一時停止します。エンター(リターン)キーを押せば先に進みます。

もし前段階の処理で何かしら問題が見つかれば、CTRL+Cで強制終了させても良いでしょう。

例2 : 「ok? (y/N):」

Yと入力しないと実行しない、Yあるいはy以外では終了させるようなパターンだと、このように書けます。

#!/bin/bash
  :
(前段階の処理)

read -p "ok? (y/N): " yn
case "$yn" in [yY]*) ;; *) echo "abort." ; exit ;; esac

(続きの処理)
  :

readコマンドの末尾に書いてあるynは変数です。
キー入力した結果はここに格納されるので、次の行のcaseinesacで評価し条件分岐させています。

case文ではパターンで指定が可能なので、
ここでは「大文字あるいは小文字の Y で始まるものは許可、そうでないものは終了(abort)」としています。

例3 : 「ok? (y/N):」をループ中に

例2の場合、「Y」としないとスクリプトが終了してしまいます。
これが例えば何かのループ処理中で、問題があっても飛ばすだけ、次の処理に移りたい場合もあるかと思います。

そんな場合は、このようにすると良いでしょう

#!/bin/bash
  :
for X in "Blaze" "Edge" "Chopper" "Archer"
do
  (前段階の処理)

  read -p "${X} : ok? (y/N):" yn
  case "$yn" in [yY]*) ;; *) echo "skipped." ; continue ;; esac

  (続きの処理)
done
  :

continueexitと違って、スクリプトは終了させません。次のループに進むだけです。
for文以外にもwhile文などでも使えます。

余録 : readコマンドのマニュアルページについて

ちなみに、man readとしてもreadコマンドのマニュアルページは出てきません。

$ man read

BUILTIN(1)                BSD General Commands Manual               BUILTIN(1)

NAME
     builtin, !, %, ., :, @, {, }, alias, alloc, bg, bind, bindkey, break, breaksw, builtins, case, cd, chdir, command, complete, continue, default, dirs, do,
     done, echo, echotc, elif, else, end, endif, endsw, esac, eval, exec, exit, export, false, fc, fg, filetest, fi, for, foreach, getopts, glob, goto, hash,
  :

これはreadが、BASHの組み込みコマンドだからです。ちょっと分かりづらいですね。

man bashとしてBASHのマニュアルページを表示したあと、SHELL BUILTIN COMMANDSの章まで進んで下さい。手元の環境だと、だいたい2,600行目あたりでした。

readコマンドにはいろいろと有用なオプションがあって、例えばパスワードを入力させる際に入力した文字列を表示させないオプションとかもあります。ちょっと全文引用するには量が多いので、是非ご自分でご確認下さい。