Bashの配列の長さはどのくらいで、「*」と「@」を区別するには?

Bashの配列の長さはどのくらいで、「*」と「@」を区別するには?

次のサンプルスクリプトがありますが、配列の長さが正確に何であるかを知りたいです。バイト、文字、または他のものですか?

#!/bin/bash

# Arrays
# @ vs. *

ape=( "Apple Banana" "Emacs Window" "Panda Bamboo Nature" )
cape=( 'Ping Pong' 'King Kong' 'King Fisher Club' 'Blurb' )
jade=( ally belly cally delly )

echo Expansion with \*
echo ${ape[*]}
echo ${cape[*]}
echo -e "${jade[*]}\n"

echo Expansion with \@
echo ${ape[@]}
echo ${cape[*]}
echo -e "${jade[@]}\n"

echo Elements with \*
echo ${#ape[*]}
echo ${#cape[*]}
echo ${#jade[*]}

echo Elements with \@
echo ${#ape[@]}
echo ${#cape[@]}
echo ${#jade[*]}

echo -e "\nLength"
echo ${#ape}
echo ${#cape}
echo ${#jade}

私が知っているマニュアルページでは、配列拡張は単語が二重引用符で囲まれている場合とは異なりますが、*違いはありません。@どちらの場合も、同じ結果が得られるのはなぜですか?

出力は次のとおりです。

Expansion with *
Apple Banana Emacs Window Panda Bamboo Nature
Ping Pong King Kong King Fisher Club Blurb
ally belly cally delly

Expansion with @
Apple Banana Emacs Window Panda Bamboo Nature
Ping Pong King Kong King Fisher Club Blurb
ally belly cally delly

Elements with *
3
4
4
Elements with @
3
4
4

Length
12
9
4

答え1

*配列を単一の文字列に拡張し、@個別に引用した文字列に拡張する様子を見逃しました。

printf 'string "%s"\n' "${cape[*]}"

これは生産します

string "Ping Pong King Kong King Fisher Club Blurb"

そして

printf 'string "%s"\n' "${cape[@]}"

これは生産します

string "Ping Pong"
string "King Kong"
string "King Fisher Club"
string "Blurb"

echo単に引数を連結して印刷するのではなく、書式printf文字列を引数で埋め、より多くの引数が指定された場合は同じ書式を繰り返すことに注意してください。

返品、

for s in "${cape[*]}"; do
    echo "$s"
done

単一の出力ラインを生成します(単一の文字列のみを繰り返します)。

for s in "${cape[@]}"; do
    echo "$s"
done

各配列要素に対して1つずつ生成します。


${array[*]}${array[@]}何らかの理由で単語の区切りとファイル名のグロービングを明示的に呼び出す場合を除き、常におよび拡張の周りに二重引用符を使用することをお勧めします。*or の使用は、@配列要素がすべて 1 つの文字列で必要かどうか個別に引用されるかによって異なります。

私の経験ではほとんど使用されていません[*]


配列の長さを取得するときに*どれを使用するかは問題ではありません。@ただし、両方を使用しないと、配列の最初の要素の文字長が得られます。

答え2

変数の割り当てに使用する他の引用に基づいて、「単語が二重引用符で囲まれた場合」というフレーズを、「配列要素が二重引用符で囲まれた場合」という意味で誤って解釈されていると思います。 「変数の単語が二重引用符で囲まれているかどうかを拡張することを意味します。」

同じ行で発生する変数拡張を使用することもできます。次echoのように、より構成可能な項目を使用すると、よりきれいな結果が得られます。printfいい仕事をしました。ナンダがやりました。) または次のようになります。

$ printf -- '->%s<-\n' "${ape[@]}"
->Apple Banana<-
->Emacs Window<-
->Panda Bamboo Nature<-

printf が実行する中間値を見ることができる場合は、次のように表示されます。

printf -- '->%s<-\n' "Apple Banana" "Emacs Window" "Panda Bamboo Nature"

引用されていないバージョンとは異なり、

$ printf -- '->%s<-\n' ${ape[@]}
->Apple<-
->Banana<-
->Emacs<-
->Window<-
->Panda<-
->Bamboo<-
->Nature<-

...ここで、中間値は次のとおりです。

printf -- '->%s<-\n' Apple Banana Emacs Window Panda Bamboo Nature

...これは、要素が拡張されたターゲットを正確に示しています。最初のケースでは変数が参照されるため、トークン化は発生しなくなり、3つの要素が得られます。 2番目のケースでは、3つの要素のそれぞれも噴射されますので、printf以下を参照してください。印刷する要素です。

配列の「長さ」は通常、構文を使用して生成された要素の数です${#ape[@]}。 bashを使って${#ape}最初の要素の長さを尋ねます。

下付き文字のない配列変数を参照することは、下付き文字がゼロの配列変数を参照するのと同じです。

これがまったく異なる値を得る理由です。

関連情報