Вот небольшая (вероятно, очень специфичная для bash) функция, включающая косвенное обращение к переменной bash и unset
; это общее решение, которое не включает в себя замену текста или отбрасывание пустых элементов и не имеет проблем с цитированием / пробелами и т. д.
delete_ary_elmt() {
local word=$1 # the element to search for & delete
local aryref="$2[@]" # a necessary step since '${!$2[@]}' is a syntax error
local arycopy=("${!aryref}") # create a copy of the input array
local status=1
for (( i = ${#arycopy[@]} - 1; i >= 0; i-- )); do # iterate over indices backwards
elmt=${arycopy[$i]}
[[ $elmt == $word ]] && unset "$2[$i]" && status=0 # unset matching elmts in orig. ary
done
return $status # return 0 if something was deleted; 1 if not
}
array=(a 0 0 b 0 0 0 c 0 d e 0 0 0)
delete_ary_elmt 0 array
for e in "${array[@]}"; do
echo "$e"
done
# prints "a" "b" "c" "d" in lines
Используйте его как delete_ary_elmt ELEMENT ARRAYNAME
без $
сигилы. Включите == $word
for == $word*
для совпадений префиксов; использовать ${elmt,,} == ${word,,}
для совпадений без учета регистра; и т.д., все, что [[
поддерживает bash .
Он работает, определяя индексы входного массива и повторяя их в обратном порядке (поэтому удаление элементов не нарушает порядок итераций). Чтобы получить индексы, вам нужно получить доступ к входному массиву по имени, что можно сделать с помощью косвенного обращения к переменной bash x=1; varname=x; echo ${!varname} # prints "1"
.
Вы не можете получить доступ к массивам по имени, например aryname=a; echo "${$aryname[@]}
, это дает вам ошибку. Вы не можете этого сделать aryname=a; echo "${!aryname[@]}"
, это дает вам индексы переменной aryname
(хотя это не массив). Что ДЕЙСТВИТЕЛЬНО работает, так это то aryref="a[@]"; echo "${!aryref}"
, что будет печатать элементы массива a
, сохраняя цитирование слов оболочки и пробелы точно так же, как echo "${a[@]}"
. Но это работает только для печати элементов массива, а не для печати его длиной или индексов ( aryref="!a[@]"
или aryref="#a[@]"
или "${!!aryref}"
или "${#!aryref}"
, все они терпят неудачу).
Поэтому я копирую исходный массив по его имени через косвенную адресацию bash и получаю индексы из копии. Чтобы перебирать индексы в обратном порядке, я использую цикл for в стиле C. Я также мог бы сделать это, обратившись к индексам через ${!arycopy[@]}
и изменив их с помощью tac
, которая cat
меняет порядок строк ввода.
Функциональное решение без косвенного eval
обращения к переменным, вероятно, должно быть задействовано , что может быть безопасным или небезопасным для использования в этой ситуации (я не могу сказать).
zsh
.