慣用的なbashでこの関数を書くには?

慣用的なbashでこの関数を書くには?

私は初めてBashシェルスクリプトに触れ、次のコードを書いています。他の方法では動作できませんが、このコードは非常に粗雑なコードのようです。

誰かがこのコードを寛容な(安全で簡潔で読みやすい)Bashで書き直すのを手伝うことはできますか?特に、関数から値を返すより良い方法があるのか​​、ifステートメントでそれを正しくテストしているのか疑問に思います。 (if文に括弧を使用する必要がありますか?)

#!/bin/bash

input() {
    read -p $'\e[31m\e[1m'"$1"$' [Y/n] \e[0m' -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]
    then
        return 0
    fi
    return 1
}

if input "Upgrade Arch?"
then
    sudo pacman -Syu
fi

答え1

単に文で関数を終了すると、関数の戻りコードが文自体の戻りコードになります。

小切手が[[ $REPLY =~ ^[Yy]$ ]]よさそうです。 bashに組み込まれている角かっこテストを使用しているため、変数内でトークン化が発生しないため、変数を引用する必要はありません。正規表現チェックを使用することをお勧めしますが、より単純なグローバルマッチングも[[ $REPLY = [Yy] ]]機能します。

私がする主な変更点は、関数内でローカル変数を使用してそれをに渡すことですread。これをatlocalまたはuseとマークするdeclareと、関数内で変数をローカルで使用できます。

errexit最後に、オプション(-e)、nounset()、およびスクリプトを有効にして-uより安全にすることをお勧めします。pipefailこれは、コマンドが失敗した後にスクリプトが続行するのを防ぎ、変数名のタイプミスを見つけるのに役立ちます。このような場合は、より防御的にコーディングする必要がありますが(ほとんどのコマンドでバグを明示的にテストし、設定できない可能性がある環境変数にデフォルト値を使用する)、予期しない中断が発生したときにデバッグが簡単になります。

一緒に入れてください:

#!/bin/bash

set -eu -o pipefail

input() {
    declare confirm
    declare -r prompt=${1:-"Confirm?"}
    read -p $'\e[31m\e[1m'"${prompt}"$' [Y/n] \e[0m' -n 1 -r confirm
    echo
    [[ $confirm =~ ^[Yy]$ ]]
}

if input "Upgrade Arch?" ; then
    sudo pacman -Syu
fi

そして@StéphaneChazelas提案するとさらに改善することができます。

set -eu -o pipefail

input() {
    declare confirm
    declare -r prompt=${1:-"Confirm?"}
    IFS= read -p $'\e[31;1m'"${prompt}"$' [Y/n] \e[m' -n 1 -r confirm
    echo >&2
    [[ $confirm = [Yy] ]]
}

if input "Upgrade Arch?" ; then
    sudo pacman -Syu
fi

関連情報