У меня есть функция для отображения индекса выбранного элемента. Я пытаюсь передать параметр в функцию, чтобы использовать его как имя массива. Это работает:
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 к результату. Добавьте второй аргумент к функции, который сообщит ей, с какого числа начинать или какое число добавлять к результату, и добавьте разумное значение по умолчанию для случаев, когда второй аргумент отсутствует. Или выполните цикл по индексам какг-н.spuraticпредполагает.