web-dev-qa-db-ja.com

タイムアウト付きのユーザー入力

スクリプトを使用して、外部ダイビングのコンテンツを管理しています。最後に、ユーザーにドライブを残すか、マウント解除するオプションを提供したいと思います。ユーザーが応答しなかった場合、タイムアウトを追加し、2番目のオプション(何もしない)を使用します。

私はLinuxにかなり慣れていないので、これまでに見つけた参考文献は、現在のレベルのlinux-nessにはわかりにくいです。リファレンスライターは、誰もがすでにLinuxに堪能であると想定しているようです。 :)

これにタイムアウトを追加するにはどうすればよいですか、タイムアウトとデフォルトのアクションでこれを行うより良い方法はありますか?

注:「myDrives」は、ファイルのクローズなどを処理してマウント解除するための独自のプログラムです

echo "Do you want to un-Mount the External Drives?"
echo ""
select yn in "yes" "no"; do
  case $yn in
    yes ) Sudo myDrives --unmount; 
          break;;
    no ) break;;
  esac
done
kill -9 $PPID
3
LinuxFerLife

Bash readビルトインの-t timeoutオプションを使用して、これを行う1つの方法を次に示します。

#!/bin/bash

while :
do
  read -t10 -p "Do you want to un-Mount the External Drives? (Y/N): "
  if [ $? -gt 128 ]; then
    echo "timed out waiting for user response"
    break
  fi

  case $REPLY in
  [yY]*)
    echo "do it"
    break
    ;;
  [nN]*)
    echo "don't do it"
    break
    ;;
  *) echo "Please enter Y or N"
     ;;
  esac
done

Bashプロンプトのhelp readまたはman bashを参照してください。

3
steeldriver

これを行う別の方法を次に示します。

#!/bin/bash

printf "%s\n" "Do you want to un-Mount the External Drives?" 
timeout --foreground 10 bash -c '
    select sel in "yes" "no"
    do
        echo "$REPLY"
        break
    done' | while read -r answer; do
        echo ">>Got from user: $answer"
        case "$answer" in
            "yes") echo "Unmounting stuff" ;;
        esac
done

注意すべきキーポイント:

  • timeoutには、シェルコマンドではなく、実際のプロセスが必要です。ここでは、bash Shellを個別のプロセスとして生成し、selectを駆動する仕事をさせます。
  • printfは、timeoutの外部で使用され、パイプを介してテキストを送信しないようにします
  • while read -r answer; do . . .doneは、パイプ経由で何かを受け取った場合にのみ動作します。したがって、前のbashプロセスがタイムアウトした場合、それは実行されません-何もしないというデフォルトのアクションがあります。
  • whileループがパイプを介して何かを受け取った場合、それがyes応答であるかどうかをチェックします。そうでない場合は、何も行いません
1