web-dev-qa-db-ja.com

Bash完了のコンテキストでの$ {array [*]}対$ {array [@]}についての混乱

私は初めてBashの補完を書くのに苦労しており、Bash配列を逆参照する2つの方法について少し混乱しています(${array[@]}および${array[*]})。

関連するコードの塊は次のとおりです(ちなみに動作しますが、もっとよく理解したいと思います)。

_switch()
{
    local cur perls
    local ROOT=${PERLBREW_ROOT:-$HOME/Perl5/perlbrew}
    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}
    perls=($ROOT/perls/Perl-*)
    # remove all but the final part of the name
    perls=(${perls[*]##*/})

    COMPREPLY=( $( compgen -W "${perls[*]} /usr/bin/Perl" -- ${cur} ) )
}

Bashの ドキュメントによる

配列の任意の要素は、$ {name [subscript]}を使用して参照できます。中括弧は、シェルのファイル名展開演算子との競合を避けるために必要です。添え字が「@」または「*」の場合、Wordは配列名のすべてのメンバーに展開されます。これらの添え字は、Wordが二重引用符で囲まれている場合にのみ異なります。 Wordが二重引用符で囲まれている場合、$ {name [*]}は各配列メンバーの値がIFS変数の最初の文字で区切られた単一のWordに展開され、$ {name [@]}はnameの各要素を展開します別のWordに。

今、私は_compgen -Wは、可能な選択肢のワードリストを含む文字列を想定していますが、このコンテキストでは、「$ {name [@]}がnameの各要素を個別のWordに展開する」という意味がわかりません。

長い話:${array[*]}動作します。 ${array[@]}しません。理由を知りたい、そして何を正確に理解したいのか_${array[@]}に展開されます。

68
Telemachus

(これは、カレブ・ペダーソンの答えに対する私のコメントの拡張です-_[@]_対_[*]_のより一般的な扱いについては、その答えを参照してください。)

Bash(または同様のシェル)がコマンドラインを解析するとき、一連の「単語」に分割します(後で混乱を避けるために「シェル単語」と呼びます)。一般に、シェルワードはスペース(または他の空白)で区切られますが、スペースをエスケープまたは引用することでシェルワードに含めることができます。二重引用符で囲まれた_[@]_と_[*]_-拡張配列の違いは、_"${myarray[@]}"_が配列の各要素を個別のシェルワードとして処理する一方で、_"${myarray[*]}"_配列のすべての要素がスペース(またはIFSの最初の文字が何であれ)で区切られた単一のシェルワードになります。

通常、_[@]_の動作が必要です。 perls=(Perl-one Perl-two)があり、_ls "${perls[*]}"_を使用するとします。これは_ls "Perl-one Perl-two"_と同等で、_Perl-one Perl-two_という名前の単一のファイルを検索します。 _ls "${perls[@]}"_は_ls "Perl-one" "Perl-two"_と同等です。

compgenに補完語(シェル語との混同を避けるためにcomp-wordと呼びます)のリストを提供することは異なります。 _-W_オプションはコンプワードのリストを取りますが、コンプワードがスペースで区切られた単一のシェルワードの形式でなければなりません。 (少なくとも私の知る限り)常に引数を取るコマンドオプションは、単一のShell-Wordを取ることに注意してください。そうしないと、オプションへの引数が終了するタイミングと、通常のコマンド引数(/ otherオプションフラグ)開始。

さらに詳細に:

_perls=(Perl-one Perl-two)
compgen -W "${perls[*]} /usr/bin/Perl" -- ${cur}
_

以下と同等です:

_compgen -W "Perl-one Perl-two /usr/bin/Perl" -- ${cur}
_

...あなたが望むことをします。一方、

_perls=(Perl-one Perl-two)
compgen -W "${perls[@]} /usr/bin/Perl" -- ${cur}
_

以下と同等です:

_compgen -W "Perl-one" "Perl-two /usr/bin/Perl" -- ${cur}
_

...これは完全なナンセンスです。「Perl-one」は-Wフラグに接続された唯一のcomp-Wordであり、最初の実際の引数(compgenは文字列として完成する)は「Perl-two」です。/usr/bin/Perl」。 compgenは追加の引数( "-"および$ curにあるもの)が与えられていると文句を言うと思われますが、どうやらそれらは無視されるようです。

86
Gordon Davisson