試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

シェルスクリプトでユーザからの入力を受け付け、複数の階層を持ったメニューを作る

readコマンドでユーザからの入力を受け付けてcase構文を用いてその内容を処理するという流れをシェルスクリプトの中で用いることで、ユーザからの入力を処理できる。
下は例。

#! /bin/sh

show_mainmenu()
{
  while true; do
    cat <<EOF
メインメニュー
1:サブメニュー1
2:サブメニュー2
3:終了
数字を入力してください
EOF
    # キー入力をACT_MAINに代入
    read ACT_MAIN
    # キー入力された値によって分岐
    case ${ACT_MAIN} in
     1)
      show_submenu1
      break
      ;;
     2)
      show_submenu2
      break
      ;;
     3)
      break
      ;;
     *)
      printf "エラー: 無効な項目 \"%s\" が入力されました\n" "${ACT_MAIN}"
      ;;
    esac
  done
}

show_submenu1()
{
  while true; do
    cat <<EOF
サブメニュー1
1:メニュー項目1-1
2:メニュー項目1-2
3:メインメニューに戻る
数字を入力してください
EOF
    read ACT_SUB1
    case ${ACT_SUB1} in
     1)
      echo "メニュー項目1-1が選択されました"
      break
      ;;
     2)
      echo "メニュー項目1-2が選択されました"
      break
      ;;
     3)
      show_mainmenu
      break
      ;;
     *)
      printf "エラー: 無効な項目 \"%s\" が入力されました\n" "${ACT_SUB1}"
      ;;
    esac
  done
}

show_submenu2()
{
  while true; do
    cat <<EOF
サブメニュー2
1:メニュー項目2-1
2:メニュー項目2-2
3:メインメニューに戻る
数字を入力してください
EOF
    read ACT_SUB2
    case ${ACT_SUB2} in
     1)
      echo "メニュー項目2-1が選択されました"
      break
      ;;
     2)
      echo "メニュー項目2-2が選択されました"
      break
      ;;
     3)
      show_mainmenu
      break
      ;;
     *)
      printf "エラー: 無効な項目 \"%s\" が入力されました\n" "${ACT_SUB2}"
      ;;
    esac
  done
}

# ここから処理開始
show_mainmenu

これを実行すると

メインメニュー
1:サブメニュー1
2:サブメニュー2
3:終了
数字を入力してください

というメニューが出るので、それぞれの数字を入力してEnterを押す。「1」にすると

サブメニュー1
1:メニュー項目1-1
2:メニュー項目1-2
3:メインメニューに戻る
数字を入力してください

のようにサブメニューが表示され、次に選択した項目によって

メニュー項目1-1が選択されました

のようにメッセージが出力されて終了する。サブメニューで「3」を選択するとメインメニューに戻り、メインメニューで「3」を選択すると終了する。
無効な文字列を入力すると

エラー: 無効な項目 "foo" が入力されました

のように表示されて元の入力に戻る。
なお、無限ループの記述では、bashzshでは

for ((;;)); do
...
done

と書くこともできるが、シェル依存となるので、dashでも動作するように

while true; do
...
done

とした。