Bash arrayは複数の値を一variableに保持し、quoted “${array[@]}”で各要素の境界を保てます。POSIX shのportable機能ではなくBash固有です。空要素、space、sparse index、associative key、順序を理解し、command outputをunquotedでarray化しません。
結論は「順序付きlistはdeclare -a、key/valueはdeclare -Aを使い、assignmentと展開を常にquoteします。fileの各lineはmapfile -tまたはwhile readで読み、要素数・index・空要素をtestします」です。
indexedとassociativeを選ぶ基準
Bashではsubscriptに整数を使うindexed arrayと文字列keyを使うassociative arrayがあります。indexed arrayは0からの連続を保証せず、要素削除後はsparseになります。associative arrayのiteration順を業務順序として依存しません。
- scriptがBashで実行されること
- indexed順序かkey lookupのどちらが必要か
- empty element・space・newlineを保持するか
- input sizeと最大要素数
- set -u環境でempty arrayを扱う方法
declare -p arrayでtypeと内容を確認し、要素数は${#array[@]}、indexは${!array[@]}で取得します。表示時も機密値を含まないsampleに限定します。command substitutionをunquotedでarray assignmentへ入れる方法はword splittingとglobを起こすため避けます。
Bash arrayはindexedとassociativeの二種類で、POSIX shには同じ機能がありません。scriptのshebangと実際のinterpreterを確認し、declare -pで型、${#array[@]}で要素数、${!array[@]}でindexまたはkeyを読みます。0要素、空文字一要素、sparse indexを区別し、入力がline、NUL区切り、CSV、JSONのどれかに応じて読込方法を選びます。
要素境界を壊さず代入する
literal listはitems=(“one” “two words” “”)とquoteして作ります。fileのlineはmapfile -tへredirectし、NUL-separated pathはread -d ”等を使います。functionへ渡すときは”${items[@]}”で展開し、受け側は”$@”として再構築します。
indexed arrayを作る
items=("alpha" "two words" "")
printf 'count=%s\n' "${#items[@]}"
printf '<%s>\n' "${items[@]}"
quoted [@]でspaceとempty elementを個別要素として渡します。
要素を追加
items+=("omega")
printf 'last=%s\n' "${items[-1]}"
negative indexのsupport/versionを対象Bashで確認し、portable性が必要なら明示indexを使います。
indexと値をloop
for i in "${!items[@]}"; do
printf 'index=%s value=<%s>\n' "$i" "${items[i]}"
done
sparse indexでも実在indexを列挙できます。
associative array
declare -A ports=([http]=80 [https]=443)
printf 'https=%s\n' "${ports[https]}"
keyの許可範囲を決め、iteration orderへ依存しません。
fileを一line一要素で読む
mapfile -t lines < ./input.txt
printf 'lines=%s\n' "${#lines[@]}"
-tはdelimiter newlineを取り除き、巨大fileではmemory上限を確認します。
indexed arrayはitems=(“alpha beta” gamma)のように各要素をquoteし、展開は”${items[@]}”を使います。associative arrayはdeclare -A mapを先に宣言し、許可されたkeyで値を設定します。line単位の小規模入力はmapfile -t、巨大fileはwhile readで逐次処理します。外部commandの出力をarr=($(command))で受けず、delimiterを保つ方法を選びます。
追加・iterationと[@]・[*]・sparse indexを理解する
“${array[@]}”は各要素を別wordとして展開し、”${array[*]}”はIFS先頭文字で一つのwordへ結合します。quoteしない展開は各要素をさらにword splittingとfilename expansionへかけます。${#array[@]}はelement countで、最大index+1とは限りません。
- Bash arrayはPOSIX shでportableな機能ではない
- indexed arrayのsubscriptはarithmetic expressionとして評価される
- associative arrayはdeclare -Aで宣言する
- quoted [@]は各elementを別wordとして保持する
- mapfile/readarrayはstandard inputのlineをindexed arrayへ読む
quoteされた${array[@]}は各要素を別wordとして保持し、${array[*]}はIFS先頭文字で一つのwordへ結合します。unquoted展開は各値をさらにword splittingとglobへ通します。indexed arrayのsubscriptはarithmetic expressionとして評価され、associative arrayのkeyとは意味が異なります。要素数は最大index+1とは限らず、unset後のsparse arrayでは特に違います。
外部inputとkeyを安全に扱う
untrusted keyをarithmetic subscriptへ直接入れず、indexed/associativeの型を明示します。大量fileをmapfileでmemoryへ全部読む前にsize上限を確認します。array要素をevalやshell codeへ連結せず、command argumentとしてquoted展開します。
- unquoted command substitutionで空白とglobを壊す
- “${array[*]}”と”${array[@]}”を同じだと思う
- element countをlast indexとみなす
- associative arrayのiteration順を保証とする
- shでBash array syntaxを実行する
untrusted値をindexed subscriptへ直接使わず、整数形式と範囲を検証します。associative keyも許可文字と長さを制限し、evalで配列参照を組み立てません。mapfileは入力全体をmemoryへ載せるためsize上限を確認します。secretを含むarrayをdeclare -pやset -xでログへ出さず、function引数へ渡す場合もprocess環境やcommand line露出を避けます。
空arrayと特殊文字をtestする
0要素、empty一要素、space、newline、wildcard、leading dash、sparse index、associative keyをtestします。declare -p、element count、index list、functionへ渡ったargcを比較し、意図しない再分割がないことを確認します。
- Bash interpreterとarray typeを明示した
- quoted [@]でelement境界を保持した
- empty・space・sparse・keyをtestした
- input sizeとuntrusted subscriptを制限した
空配列、空文字要素、space、tab、newline、wildcard、leading dash、sparse index、重複keyを含むfixtureで、要素数と各値の境界をprintf ‘<%s>\n’等で確認します。”${array[@]}”をfunctionへ渡したときのargcを比較し、保存・再読込で欠落しないかtestします。shで起動した場合は早期に明確なerrorを出すことも確認します。
用途に合うdata structureを選ぶ
順序付き少数listはindexed、name lookupはassociative arrayを使います。巨大data、nested structure、JSON、並列更新が必要ならshell arrayで無理に表現せず専用language/parserへ移します。
順序付きの小規模listはindexed、name lookupはassociative arrayが向きます。nested object、巨大data、JSON、複雑なvalidationが必要ならshell arrayで無理に表現せずjqやPython等を使います。POSIX portable scriptが要件ならBash arrayを避け、改行やNUL区切りstreamと明確なparserを設計します。

コメント