web-dev-qa-db-ja.com

bash-選択を選択して実行した後で選択メニューを再表示するにはどうすればよいですか

2つの機能を持つテーマ用のツールスクリプトを作成しています:更新の確認、テーマの再インストール

だからここに選択メニューのコードがあります:

PS3='Choose an option: '
options=("Check for update" "Reinstall theme")
select opt in "${options[@]}"
do
     case $opt in
             "Check for update")
                       echo "Checking update"
                               ;;
             "Reinstall theme")
                       echo "Reinstalling"
                               ;;
                               *) echo invalid option;;
     esac
done

走るとこんな感じ

1) Check for update
2) Reinstall theme
Choose an option:

1と入力して入力すると、更新の確認コマンドが実行されます

問題は、スクリプトの実行が終了すると、メニューではなく「オプションを選択:」が再表示されることです。したがって、メニューがないと(特に長いスクリプトの後)、ユーザーが選択しにくくなる可能性があります。

1) Check for update
2) Reinstall theme
Choose an option: 1
Checking update
Choose an option:

オプションを実行した後でメニューを再表示するにはどうすればよいですか

8
superquanganh

私はあなたが本当にこのようなものを望んでいると思います:

check_update () {
    echo "Checking update"
}

reinstall_theme () {
    echo "Reinstalling theme"
}

while true; do
    options=("Check for update" "Reinstall theme")

    echo "Choose an option:"
    select opt in "${options[@]}"; do
        case $REPLY in
            1) check_update; break ;;
            2) reinstall_theme; break ;;
            *) echo "What's that?" >&2
        esac
    done

    echo "Doing other things..."

    echo "Are we done?"
    select opt in "Yes" "No"; do
        case $REPLY in
            1) break 2 ;;
            2) break ;;
            *) echo "Look, it's a simple question..." >&2
        esac
    done
done

最初のcaseステートメントを小さく保つために、タスクを個別の関数に分けました。 caseステートメントではオプション文字列ではなく$REPLYも使用しました。これは短いため、変更しても、両方の場所で更新することを忘れても壊れないためです。また、スクリプトのselect呼び出しに影響する可能性があるため、PS3には触れないように選択しています。別のプロンプトが必要な場合は、一度設定してそのままにします(多分PS3="Your choice: ")。これにより、複数の質問を含むスクリプトがより統一された感じになります。

ユーザーが完了するまですべてを繰り返す外部ループを追加しました。最初のselectステートメントで質問を再表示するには、このループが必要です。

breakcaseステートメントに追加しました。そうしないと、スクリプトを中断する以外に終了する方法がありません。

selectの目的は、ユーザーから1つの質問に対する回答を得ることであり、実際には(それ自体が)スクリプトのメインイベントループになることではありません。一般に、select-caseは実際に変数を設定するか、関数を呼び出してから続行する必要があります。

最初のselectに「Quit」オプションを組み込んだ短いバージョン:

check_update () {
    echo "Checking update"
}

reinstall_theme () {
    echo "Reinstalling theme"
}

while true; do
    options=("Check for update" "Reinstall theme" "Quit")

    echo "Choose an option: "
    select opt in "${options[@]}"; do
        case $REPLY in
            1) check_update; break ;;
            2) reinstall_theme; break ;;
            3) break 2 ;;
            *) echo "What's that?" >&2
        esac
    done
done

echo "Bye bye!"
10
Kusalananda

私はこのトリックを使います:

options=("First option" "Second option" "Quit")
PS3="So what? "
select opt in "${options[@]}"
do
    case $opt in
        "First option")
            echo "First option"
            ;;
        "Second option")
            echo "Second option"    
            ;;
        "Quit")
            echo "We are done..."
            break
            ;;
        *) 
            PS3="" # this hides the Prompt
            echo asdf | select foo in "${options[@]}"; do break; done # dummy select 
            PS3="So what? " # this displays the common Prompt
            ;;
    esac
done
3
xerostomus

Doループは無限であり、selectステートメントはその外側にあります。スクリプトは、selectステートメントを1回実行した後、$ optケースの繰り返しを確認するdoループチェックを続けます。私の推奨は、次のようなケースステートメントの後に休憩を入れることです。

esac
break
done

次に、スクリプト全体を何度も繰り返したい場合は、selectステートメントからdoneステートメントまでをすべて囲む別のループを作成します。

2
bashBedlam