Як я можу повністю видалити елемент із масиву?


48

unset array[0]видаляє елемент, але все-таки якщо я echo ${array[0]}отримаю нульове значення, крім того, є й інші способи цього зробити, але якщо елемент масиву містить пробіли, як нижче

array[0]='james young'
array[1]='mary'
array[2]='randy orton'

але вони також не справляються із завданням

array=${array[@]:1} #removed the 1st element

тепер я хочу, щоб новий масив був подібний

array[0]='mary'
array[1]='randy orton'

Пробіли викликають проблеми після призначення, а власне масив стає подібним до підстановки.

array=(mary randy orton)

4
Ні, не пробіли викликають неприємності, а відсутність цитування.
манатура

Відповіді:


68

Просто використовуйте синтаксис масиву у призначенні та цитуйте змінну:

array=("${array[@]:1}") #removed the 1st element

Відредагуйте відповідно до запитання в коментарі. Для $@ви можете використовувати його як це:

set -- "${@:2}" #removed the 1st parameter

8
Зауважте, що він не видаляє 1-й елемент, а елемент індексу 0 і переназначає індекси. Якщо перший елемент був на індексі 12, він нічого не видалить, але переназначить індекси так, що те, що колись було в індексі 12, тепер стане індексом 0. Це, мабуть, не викликає занепокоєння у справі ОП, але, мабуть, слід зазначити майбутня довідка. Поведінка відрізняється zsh, масиви яких не є рідкісними всупереч ksh або bash.
Стефан Шазелас

3
Привіт @StephaneChazelas. Особливістю "індексів" є " індекс ". Дякуємо за Ваш коментар!
Стівен Лу

3
@manatwork - re: ваша редакція - чому б не використовувати shift?
don_crissti

1
@don_crissti, хороший момент. Я зосередився на різниці в індексації і не думав далі. Також мав на увазі ситуацію, коли потрібно викинути змінну кількість предметів, наприклад, щоб зберегти саме останні 3: array=("${array[@]: -3}")та set -- "${@: -3}". Так застрягли в індексах.
манатство

1
shift $[$#-3]останні 3, мабуть, набагато швидше для$@
Тіно

0

Це змусило мене подумати. Проблема sed / awk / tail полягає в тому, що вони розташовуються по черзі. Після видалення першого рядка потрібно записати всі інші рядки з простору шаблону у файл.

  • Ви можете використовувати наступні команди, щоб робити те, що ви хочете за лічені секунди.
  • Це запише весь файл у масив.
  • Видаліть перший рядок, оскільки він скидає його назад у файл.

    readarray -t aLargeFile < <(cat largefile)
    echo "${aLargeFile[@]:1}" >largefile

Просто змініть largefileім'я файлу.


Чому б не використовувати sed -i 1d largefileзамість цього? Це працює навіть для файлів більше RAM + swap
Tino

0

Щоб видалити елемент у певному індексі, ми можемо скористатися, unsetа потім скопіювати в інший масив. unsetУ цьому випадку лише просто не потрібно. Оскільки unsetне видаляє елемент, він просто встановлює нульовий рядок до конкретного індексу масиву.

declare -a arr=('aa' 'bb' 'cc' 'dd' 'ee')
unset 'arr[1]'
declare -a arr2=()
i=0
for element in ${arr[@]}
do
    arr2[$i]=$element
    ((++i))
done
echo ${arr[@]}
echo "1st val is ${arr[1]}, 2nd val is ${arr[2]}"
echo ${arr2[@]}
echo "1st val is ${arr2[1]}, 2nd val is ${arr2[2]}"

Вихід є

aa cc dd ee
1st val is , 2nd val is cc
aa cc dd ee
1st val is cc, 2nd val is dd

-1
#!/bin/bash

q=( one two three four five )

echo -e "
  (remove) { [:range:] } <- [:list:]
                | [:range:] => return list with range removed range is in the form of [:digit:]-[:digit:]
"

function remove {
  if [[ $1 =~ ([[:digit:]])(-([[:digit:]]))?   ]]; then
    from=${BASH_REMATCH[1]}
    to=${BASH_REMATCH[3]}
  else
    echo bad range
  fi;shift
  array=( ${@} )
  local start=${array[@]::${from}}
  local rest
  [ -n "$to" ] && rest=${array[@]:((${to}+1))}  || rest=${array[@]:((${from}+1))}
  echo ${start[@]} ${rest[@]}
}

q=( `remove 1 ${q[*]}` )
echo ${q[@]}
~                                                                                                                                                              
~                       

4
Це було б набагато краще, якби щось пояснило, як це працює, а не просто крапку коду. А що з тильдами внизу?
CVn

3
Серйозно, ви маєте рацію. Схоже, це написав хуліган, але дякую. Мені реально лише прокрасти це між днями порції гамбургерів.
MageProspero

Якщо в будь-якому елементі q є пробіли, це розбиває його на кілька елементів.
Вільям Еверетт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.