Wie kann ich ein Element vollständig aus einem Array entfernen?

48

unset array[0]Entfernt das Element, aber wenn ich echo ${array[0]}einen Nullwert erhalte, gibt es noch andere Möglichkeiten, dies zu tun, aber wenn ein Element eines Arrays Leerzeichen wie unten enthält

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

Aber auch diese machen ihren Job nicht

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

Jetzt möchte ich, dass das neue Array so aussieht

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

Die Leerzeichen verursachen nach der Zuweisung Probleme, und das tatsächliche Array wird durch Substitution ersetzt.

array=(mary randy orton)
münchen
quelle
4
Nein, nicht die Leerzeichen verursachen Ärger, sondern das Fehlen von Zitaten.
Manatwork

Antworten:

68

Verwenden Sie einfach die Array-Syntax für die Zuweisung und zitieren Sie Ihre Variable:

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

Bearbeiten Sie nach Frage im Kommentar. Für $@Sie kann es so verwendet werden:

set -- "${@:2}" #removed the 1st parameter
Mann bei der Arbeit
quelle
8
Beachten Sie, dass nicht das 1. Element, sondern das Element von Index 0 entfernt und die Indizes neu zugewiesen werden. Wenn sich das erste Element in Index 12 befand, wird nichts entfernt, die Indizes werden jedoch neu zugewiesen, sodass das, was sich früher in Index 12 befand, jetzt in Index 0 angezeigt wird. Dies ist im Fall des OP wahrscheinlich kein Problem, sollte jedoch beachtet werden Zukunftsbezug. Anders zshverhält es sich mit Arrays, die im Gegensatz zu ksh oder bash nicht spärlich sind.
Stéphane Chazelas
3
Hi @StephaneChazelas. Der Singular von "Indizes" ist " Index ". Vielen Dank für Ihren Kommentar!
Steven Lu
3
@manatwork - re: your edit - warum nicht mit shift?
don_crissti
1
@don_crissti, guter Punkt. Ich habe mich auf den Unterschied bei der Indizierung konzentriert und nicht weiter darüber nachgedacht. Denken Sie auch an die Situation, in der Sie eine variable Anzahl von Elementen verwerfen müssen, um beispielsweise genau die letzten 3: array=("${array[@]: -3}")und 3: beizubehalten set -- "${@: -3}". Also bei Indizes stecken.
Manatwork
1
shift $[$#-3]für die letzten 3 ist wahrscheinlich viel schneller für$@
Tino
0

Das hat mich zum Nachdenken gebracht. Das Problem mit sed / awk / tail ist, dass sie zeilenweise sind. Nachdem Sie die erste Zeile gelöscht haben, müssen Sie jede zweite Zeile aus dem Musterbereich in die Datei schreiben.

  • Mit den folgenden Befehlen können Sie in Sekundenschnelle das tun, was Sie wollen.
  • Dadurch wird die gesamte Datei in ein Array geschrieben.
  • Entfernen Sie die erste Zeile, wenn Sie sie wieder in die Datei kopieren.

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

Ändern Sie einfach largefileden Namen Ihrer Datei.

jgshawkey
quelle
Warum nicht sed -i 1d largefilestattdessen verwenden? Dies funktioniert sogar für Dateien, die größer als RAM + Swap sind
Tino
0

Um ein Element an einem bestimmten Index zu entfernen, können Sie es verwenden unsetund dann in ein anderes Array kopieren. Nur eben unsetist in diesem Fall nicht erforderlich. Da unsetdas Element nicht entfernt wird, wird lediglich eine Nullzeichenfolge für den bestimmten Index im Array festgelegt.

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]}"

Ausgabe ist

aa cc dd ee
1st val is , 2nd val is cc
aa cc dd ee
1st val is cc, 2nd val is dd
Rashok
quelle
-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[@]}
~                                                                                                                                                              
~                       
MageProspero
quelle
4
Das wäre viel besser, wenn es etwas zu erklären gäbe, wie es funktioniert, und nicht nur einen kleinen Code. Und was ist mit den Tilden unten?
ein Lebenslauf vom
3
Im Ernst, Sie haben Recht. Das sieht so aus, als ob es von einem Hooligan geschrieben wurde, aber danke. Ich kann das wirklich nur zwischen den Hamburger-Serviertagen machen.
MageProspero
Wenn ein Element von q Leerzeichen enthält, wird es in mehrere Elemente aufgeteilt.
William Everett