シェル関数の他の変数に$@を代入

シェル関数の他の変数に$@を代入

gcgitコミット/チェックアウトを区別できるスマートエイリアスを作成しています。

引数なしで呼び出すか、引数を使用して呼び出すとgcgit commitが実行されます。それ以外の場合は、git checkoutを実行します(追加のパラメータを持つフラグがある場合)。 gcの他のバリエーションが呼び出されると、予期しない操作を実行するのではなく、エラーを発生させたいと思います。-a-mb

これはこれまで私のシェル機能です。

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
}

しかし、これは正しく動作しません。いくつかの実験では、他の変数に割り当てることが根本的な原因であることがわかりましたが、なぜ$@そして正確に何が間違っているのか理解できませんでした。

また、シェル関数を書くのは今回が初めてなので、私が犯した間違いを指摘してください。

答え1

$@配列の場合は配列に割り当てます。

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'

その他の注意事項:

  • "$args[@]"zshではorの"${(@)args}"代わりに使用することもできますが、"${args[@]}"bash / kshでは使用できません。"$args"yashで動作しますが、ksh / bashではzsh(接続された要素の最初の文字)とksh / bashと同じです。 zshではこれは機能しますが、空の要素がある場合は削除されます。"$args[*]"$IFS"${args[0]}"$args
  • getopts関数で使用するときは、事前に何かを追加する必要がありますlocal OPTIND OPTARG(特に、OPTINDまたは少なくとも初期化/設定解除)。 zshはOPTIND他のシェルをエミュレートしないと自動的にこれを行いますが、ksh / bash / yashはそうではありません。関数内で使用する他の変数もローカル変数に設定する必要があります。
  • エラーはstderr(fd 2)に送信する必要がありますecho>&2 Too many arguments

答え2

他の答えはPOSIXではないので、ここに代替案があります。一時的に位置パラメータを粉砕するには、次のようにします。

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

その後、回復する準備ができたら、次の手順を実行します。

IFS='
'
set -- $s1

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

注:最後の行には引用符がない変数が含まれています。これは、引用されていない変数が許容される数少ない場合(私の考えでは唯一の場合)の1つです。ユーザーが明示的に設定した場合ですIFS。ユーザーは本質的に「はい、私がしていることを知っています。続けてください」と言います。 。

関連情報