web-dev-qa-db-ja.com

シェル関数の別の変数に$ @を割り当てます

Git commit/checkoutを区別できるインテリジェントなエイリアスgcを作成しています。

gcが引数なしで、または-a-m引数付きで呼び出されると、git commitが実行されます。それ以外の場合は、git checkoutが実行されます(追加の引数を持つbフラグがある場合)。 gcの他のバリエーションが呼び出された場合、予期しない何かを行うのではなく、エラーをスローすることをお勧めします。

これが私のシェル関数です。

gc() {
    args=$@
    commit=false
    checkout=false

    # Check flags
    while getopts ":am:b" opt; do
        case $opt in
            a|m)
                commit=true
                ;;
            b)
                checkout=true
                ;;
            \?)
                echo "Unknown flags passed."
                return 1
                ;;
        esac
    done

    shift "$((OPTIND-1))"

    # Check number of arguments
    if [[ "$#" == 0 ]]; then
        commit=true
    Elif [[ "$#" == 1 ]]; then
        checkout=true
    else
        echo "Too many arguments"
        return 1
    fi

    # Finally run respective command
    if [[ $commit == true && $checkout == true ]]; then
        echo "Unable to ascertain which operation you would like to perform."
        return 1
    Elif [[ $commit == true ]]; then
        git commit "$args"
    Elif [[ $checkout == true ]]; then
        git checkout "$args"
    else
        echo "Undefined behavior"
        return 1
    fi
}

ただし、これは正しく機能しません。少し実験したところ、別の変数に$@を割り当てることが根本的な原因であることがわかりましたが、その理由と正確に何が間違っているのか理解できませんでした。

また、初めてシェル関数を作成するときは、自分が犯した間違いを強調してください。

3
I.Am.A.Guy

$@は配列です。配列に割り当てます。

args=("$@")

次に、それを配列として使用します。

Elif [[ $commit == true ]]; then
    git commit "${args[@]}"
Elif [[ $checkout == true ]]; then
    git checkout "${args[@]}"
else

現在のコードで起こっていることは、すべての個別の引数が単一の文字列として格納されていることです。だからあなたが呼び出す場合:

bc -a "foo bar"

これはargsに次のように割り当てられます:

args='-a foo bar'

次に、実行する代わりに:

git commit -a "foo bar"

あなたが得る:

git commit '-a foo bar'
7
jesse_b

他の答えはPOSIXではないので、ここに代替案があります。位置の引数を一時的に破棄したい場合は、次のようにすることができます。

s1=$(printf '%s\n' "$@")

復元する準備ができたら、次の操作を行います。

IFS='
'
set -- $s1

これは、引数に改行が含まれていないことを前提としています。その場合は、別の区切り文字を使用する必要があります。

補足:気が付いたら、最後の行に引用符で囲まれていない変数が含まれています。これは、引用符で囲まれていない変数が許容される数少ないケースの1つです(私の意見では唯一のケース)。ユーザーが明示的にIFSを設定した場合です。ユーザーは本質的に「はい、私はイムが何をしているか知っています。続行してください」と言います。

3
Steven Penny