Как сбросить диапазон массива в Bash

Как сбросить диапазон массива в Bash

Я пытаюсь удалить диапазон элементов массива, но это не удается.

Мой массив

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[@]}": . К сожалению, применение диапазона к этому не работает с bashnor 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

  1. Если ваш массивнепрерывный/не редкий(все элементы из набора 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. Общее решение(работает также для разреженных массивов): Вы можете удалить 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
    

Связанный контент