我有一個功能來顯示所選元素的索引。我試圖將參數傳遞給函數以將其用作數組名稱。這有效:
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
可讀性。索引擴展為數組,這並不是絕對必要的,平面列表也可以。
也可以看看BashFAQ/006。
答案2
Bash 中的陣列是從零開始的。他們就是這樣。也就是說,如果你知道數組總是由從 1 開始的數字索引,只需在結果中添加 +1 即可。在函數中添加第二個參數,這將告訴函數從哪個數字開始或添加到結果中,並在缺少第二個參數的情況下添加合理的預設值。或將索引循環為史普拉蒂克先生建議。