Я пытаюсь удалить диапазон элементов массива, но это не удается.
Мой массив
root@ubuntu:~/work# echo ${a[@]}
cocacola.com airtel.com pepsi.com
Массив печати 0-1 выглядит нормально
root@ubuntu:~/work# echo ${a[@]::2}
cocacola.com airtel.com
Теперь я пытаюсь удалить только эти элементы, используя:
root@ubuntu:~/work# unset a[@]::2
root@ubuntu:~/work# echo ${a[@]}
Это удаление всего массива..
Что я делаю не так?
Я нашел другой способ удаления диапазона массива, но почему вышеперечисленное не работает?
for ((i=0; i<2; i++)); do unset a[$i]; done
EDIT Я тоже пытался, но безуспешно
unset -v 'a[@]::2'
решение1
Следует иметь в виду, что bash
реализованные массивы, такие ksh
как , представляют собой ассоциативные массивы, ключи которых ограничены положительными целыми числами (в отличие от других языков, таких как perl
или , zsh
например).
В:
a[123]=foo a[456]=bar a[789]=baz
В bash у вас есть ассоциативный массив с 3 элементами, тогда как в perl
, у вас будет массив с 790 элементами (789 в zsh).
В случае ksh
или возвращает первый элемент массива в списке элементов, отсортированных по ключу, где ключ больше или равен 0. Таким образом, в этом случае возвращается , а не .bash
${a[@]:0:1}
${a[123]}
${a[0]}
unset 'a[123]'
(не забудьте заключить его в кавычки, иначе он завершится ошибкой, если в текущем каталоге будет файл с именем a1, a2 или a3) имеет смысл, так как он удаляет определенный ключ в массиве.
unset 'a[@]::2'
хотя это имеет меньше смысла. bash
понимает только unset a
, unset 'a[123]'
или unset 'a[*/@]'
, все, что после него, игнорируется, поэтому unset 'a[@]::2'
и unset 'a[@]please'
делаем то же самое: сбрасываем весь массив.
Если вы хотите сбросить диапазон ключей, вам придется выполнить цикл по ключам:
Чтобы получить список ключей массива, синтаксис такой "${!a[@]}"
: . К сожалению, применение диапазона к этому не работает с bash
nor ksh
, поэтому вам понадобится временный массив:
keys=("${!a[@]}")
for i in "${keys[@]::2}"; do unset "a[$i]"; done
Теперь, если вы хотите рассматривать эти массивы как в других языках, вам не нужно использовать unset
. Например, если массив изначально не является разреженным и вы хотите сохранить его таким (то есть сдвинуть все элементы на 2 вместо того, чтобы сбрасывать первые два), вы можете сделать что-то вроде:
a=("${a[@]:2}")
То есть переназначьте массив списком элементов, которые вы хотите сохранить.
Для сравнения, с zsh
.
a=({1..20})
unset 'a[12,16]'
установит пустое значение для элементов с 12 по 16. тогда как unset 'a[16,20]'
массив будет сокращен до 15 элементов.
a=({1..20})
a[12,16]=()
(все еще с zsh
) сместит элементы 17–20 на 5 позиций, поэтому a[12]
будет содержать 17
.
решение2
Если ваш массивнепрерывный/не редкий(все элементы из набора 0..N-1)
Вы можете удалить 2-й элемент массива с помощью
unset 'a[1]'
Чтобы удалить 2-й, 3-й и 4-й элемент, можно использовать, например,
for ((i=1; i<=3; i++)); do unset "a[$i]"; done
Чтобы удалить все элементы, кроме 1-го и 2-го, можно использовать, например,
for ((i=2; i<${#a[@]}; i++)); do unset "a[$i]"; done
Общее решение(работает также для разреженных массивов): Вы можете удалить 2-й элемент массива с помощью
unset "a[$(echo ${!a[@]} | cut -d" " -f 2)]"
Чтобы удалить 2-й, 3-й и 4-й элемент, можно использовать, например,
for $(echo ${!a[@]} | cut -d" " -f 2-4) ; do unset "a[$i]"; done
Чтобы удалить все элементы, кроме 1-го и 2-го, можно использовать, например,
for $(echo ${!a[@]} | cut -d" " -f 2-) ; do unset "a[$i]"; done