Удалить последний элемент из массива
Я хочу удалить последнюю запись в моем массиве, и я хочу, чтобы массив показал мне, что у меня есть 1 запись меньше, когда я использую ${#array[@]}
. Это текущая строка, которую я использую:
unset GreppedURLs[${#GreppedURLs[@]} -1]
Пожалуйста, исправьте меня и покажите мне правильный путь.
Ответы
Ответ 1
У вас есть (почти) правильный для нерезких индексированных массивов ¹:
unset 'arr[${#arr[@]}-1]'
(Обратите внимание на одинарные кавычки: они предотвращают расширение пути).
Демо:
arr=( a b c )
echo ${#arr[@]}
3
for a in "${arr[@]}"; do echo "$a"; done
a
b
c
unset 'arr[${#arr[@]}-1]'
for a in "${arr[@]}"; do echo "$a"; done
a
b
Punchline
echo ${#arr[@]}
2
(GNU bash, версия 4.2.8 (1) -release (x86_64-pc-linux-gnu))
¹ @Wil предоставил отличный ответ, который работает для всех типов массивов
Ответ 2
Вы должны удалить пробел до -1
.
Ответ 3
Если вы хотите получить ответ, который не будет есть ваши котята, попробуйте следующее:
array=([1]=1 {2..5} [10]=6);
# declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [5]="5" [10]="6}")'
index=("${!array[@]}");
# declare -a index='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="10")'
unset 'array[${index[@]: -1}]';
# declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [5]="5")'
И там у вас есть - удаление последнего элемента. Теперь я представлю гораздо более легкий ответ, который, вероятно, отвечает вашим потребностям, но имеет оговорку:
array=([1]=1 {2..5} [10]=6);
# declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [5]="5" [10]="6}")'
array=("${array[@]::${#array[@]}-1}");
# declare -a array='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")'
Эта версия имеет ярлык. Он повторно индексирует массив и удаляет последний элемент. К сожалению, вы также можете видеть, что индекс не поддерживается. Значения и их порядок были. Если вам не нужен индекс, это, вероятно, тот ответ, который вам нужен.
Оба вышеупомянутых ответа будут также работать над bash 4 Ассоциативными массивами.
-
Выбранный ответ небезопасен. Вот пример:
array=([1]=1 {2..5} [10]=6);
# declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [5]="5" [10]="6")'
unset 'arr[${#arr[@]}-1]';
# declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [10]="6")'
Хорошо, так как вы можете видеть, что он отключает элемент с индексом 5, потому что он неправильно вычисляет индекс последнего элемента массива. Он потерпел неудачу, потому что он работал с предположением, что все массивы основаны на нулевом значении и не являются разреженными. Этот ответ терпит неудачу в массивах, начиная с чего угодно, кроме нуля, массивов, которые являются разреженными, и, очевидно, должен завершиться неудачей для ассоциативного массива с "fubar" для последнего элемента.
Ответ 4
Для любого индексированного массива (разреженного или нет), поскольку bash 4.3+ (и ksh93 +), это самый простой из решений:
unset 'array[-1]'
Кавычки необходимы, чтобы избежать расширения оболочки в bash, если -1 является арифметическим выражением или переменной. Это также работает правильно:
a=3; unset 'arr[ a - 4 * 1 ]'
Но не будет работать, если unquoted (''
), поскольку * будет расширен до списка файлов в текущем рабочем каталоге ($pwd
).
Для более старых версий bash: это работает с bash 3.0 для нерезких массивов:
unset 'arr[ ${#arr[@]}-1 ]'
Пример:
$ arr=( {a..i} ); declare -p arr
declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g" [7]="h")
$ unset 'arr[ ${#arr[@]}-1 ]'; declare -p arr
declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g")
Это работает не для разреженных массивов (с некоторыми отверстиями):
$ arr=( {a..g} [9]=i ); declare -p arr
declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g" [9]="i")
$ unset 'arr[ ${#arr[@]}-1 ]'; declare -p arr
declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g" [9]="i")
Это происходит потому, что количество элементов (${#arr[@]}
) равно 8
и 8-1
равно 7
.
Таким образом, команда будет отменена arr[7]
, которая не существует. Ничего не сделано.
Решение, которое также работает для ассоциативных массивов (во всем, что это может означать "последний элемент" в несортированном списке) заключается в создании нового массива индексов.
Затем используйте последний индекс, чтобы удалить этот элемент.
Предполагается, что arr
уже определен (для bash 3.0 +):
$ index=( "${!arr[@]}" ) # makes index non-sparse.
$ unset 'arr[${index[@]}-1]' # unset the last index.
$ declare -p arr
declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g")
Немного более портативный (работает в ksh93), который выглядит уродливым, решение:
$ arr=( {a..e} [9]=i )
$ index=( "${!arr[@]}" )
$ unset "arr[ ${index[${#index[@]}-1]} ]" # Yes, double quotes.
$ declare -p arr
declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e")
Или (опять же, двойные кавычки для ksh):
$ unset "arr[${index[@]: -1}]"
Если вы хотите избежать пробела и отрицательного числа, сделайте его переменной:
$ a="-1"; unset "arr[${index[@]:a}]"