選択した要素のインデックスを表示する関数があります。関数にパラメータを渡して、それを配列名として使用しようとしています。これは機能します:
getIndex() {
arrname=$1[@]
b=("${!arrname}")
index=1; while ((index<${#b[@]})); do
if [[ "${b[$index]}" = "$VALUE" ]]; then
echo "index is $index"; return
fi
((index++)); done
}
しかし、この関数に渡す名前の配列には、最初の要素のインデックスとしてインデックス 1 があります (配列内のパターンを取得する行番号と同様のインデックスが必要です)。
a=1
while read line; do
if [[ $line =~ ^[0-9] ]]; then
avg[$a]=`echo $line | awk '{print $6}'`
((a++));
fi
また、関数 getIndex() を実行している場合、配列の最初の要素はインデックス 0 から始まります。
そこで質問です。配列のインデックスを保存したまま、関数のパラメータに配列名を渡す方法はありますか? それとも、それを忘れて関数の回答に +1 を追加する必要があるだけかもしれません。
答え1
次の構文を使用しています:
b=("${!arrname}")
これにより、価値観配列の、新しい配列を作成b[]
するbashのデフォルトの配列インデックスは0から始まります配列のコピーを適切に初期化するには、インデックスを復元する必要があります(たとえば、eval
の出力を解析または -ingするなどdeclare -p arrname
)。
コピーを作るよりも、より良いアプローチは、インデックス値ではなく、それらを使用して配列を反復処理します。このアプローチは、スパース配列、またはゼロベース以外の標準配列 (および bash4 連想配列) でも機能します。
問題は (常にあるわけではありませんが)、 が!
二重の役割を果たしていることです。間接参照での使用は、${!name}
配列インデックスの拡張での使用と互換性がないため${!arrname[@]}
、 を使用する必要がありますeval
。
これを実装する修正バージョンを次に示します。
getIndex2() {
local arrname=$1 iidx idxs index ival val
printf -v iidx '"${!%s[@]}"' "$arrname"
eval "idxs=($iidx)"
for index in "${idxs[@]}"; do
printf -v ival '${%s[%s]}' "$arrname" "$index"
eval "val=$ival"
if [[ "${val}" = "$VALUE" ]]; then
echo "index is $index"; return
fi
done
}
printf -v var ...
読みやすさを保つために (bash-3.1+)を使用していることに注意してくださいeval
。インデックスは配列に展開されますが、これは必ずしも必要ではなく、フラットなリストでもかまいません。
参照バッシュFAQ/006。
答え2
Bashの配列はゼロベースです。そうなのです。知る配列は常に1から始まる番号でインデックス付けされるので、結果に+1を追加するだけです。関数に2番目の引数を追加して、どの番号から開始するか、または結果に追加するかを伝え、2番目の引数がない場合に適切なデフォルトを追加します。または、次のようにインデックスをループします。スプラティックさん示唆します。