Antworten:
Ich habe die Frage wie geschrieben beantwortet und dieser Code kehrt das Array um. (Das Drucken der Elemente in umgekehrter Reihenfolge, ohne das Array umzukehren, ist nur eine for
Schleife, die vom letzten Element bis auf Null herunterzählt.) Dies ist ein Standardalgorithmus zum "Ersten und Letzten Tauschen".
array=(1 2 3 4 5 6 7)
min=0
max=$(( ${#array[@]} -1 ))
while [[ min -lt max ]]
do
# Swap current first and last elements
x="${array[$min]}"
array[$min]="${array[$max]}"
array[$max]="$x"
# Move closer
(( min++, max-- ))
done
echo "${array[@]}"
Es funktioniert für Arrays mit ungerader und gerader Länge.
Ein weiterer unkonventioneller Ansatz:
#!/bin/bash
array=(1 2 3 4 5 6 7)
f() { array=("${BASH_ARGV[@]}"); }
shopt -s extdebug
f "${array[@]}"
shopt -u extdebug
echo "${array[@]}"
Ausgabe:
7 6 5 4 3 2 1
Wenn extdebug
aktiviert, BASH_ARGV
enthält das Array in einer Funktion alle Positionsparameter in umgekehrter Reihenfolge.
Unkonventioneller Ansatz (alles nicht rein bash
):
Wenn alle Elemente in einem Array nur aus einem Zeichen bestehen (wie in der Frage), können Sie Folgendes verwenden rev
:
echo "${array[@]}" | rev
Andernfalls:
printf '%s\n' "${array[@]}" | tac | tr '\n' ' '; echo
und wenn du kannst zsh
:
echo ${(Oa)array}
tac
, als das Gegenteil von cat
ganz gut zu merken, DANKE!
rev
, muss ich erwähnen, dass rev
für Zahlen mit zwei Ziffern nicht richtig funktioniert. Beispielsweise wird ein Array-Element der 12
Verwendung von rev als gedruckt 21
. Probieren Sie es aus ;-)
Wenn Sie tatsächlich das Gegenteil in einem anderen Array wollen:
reverse() {
# first argument is the array to reverse
# second is the output array
declare -n arr="$1" rev="$2"
for i in "${arr[@]}"
do
rev=("$i" "${rev[@]}")
done
}
Dann:
array=(1 2 3 4)
reverse array foo
echo "${foo[@]}"
Gibt:
4 3 2 1
Dies sollte Fälle korrekt behandeln, in denen beispielsweise ein Array-Index fehlt. array=([1]=1 [2]=2 [4]=4)
In diesem Fall können durch Schleifen von 0 zum höchsten Index zusätzliche leere Elemente hinzugefügt werden.
shellcheck
zwei Warnungen array=(1 2 3 4)
<-- SC2034: array appears unused. Verify it or export it.
echo "${foo[@]}"
<-- SC2154: foo is referenced but not assigned.
declare
Zeile ist.
declare -n
in Bash-Versionen vor 4.3 nicht funktioniert.
So tauschen Sie die Array-Positionen aus (auch bei spärlichen Arrays) (seit Bash 3.0):
#!/bin/bash
# Declare an sparse array to test:
array=([5]=101 [6]=202 [10]=303 [11]=404 [20]=505 [21]=606 [40]=707)
echo "Initial array values"
declare -p array
swaparray(){ local temp; temp="${array[$1]}"
array[$1]="${array[$2]}"
array[$2]="$temp"
}
ind=("${!array[@]}") # non-sparse array of indexes.
min=-1; max="${#ind[@]}" # limits to one before real limits.
while [[ min++ -lt max-- ]] # move closer on each loop.
do
swaparray "${ind[min]}" "${ind[max]}" # Exchange first and last
done
echo "Final Array swapped in place"
declare -p array
echo "Final Array values"
echo "${array[@]}"
Bei der Ausführung:
./script
Initial array values
declare -a array=([5]="101" [6]="202" [10]="303" [11]="404" [20]="505" [21]="606" [40]="707")
Final Array swapped in place
declare -a array=([5]="707" [6]="606" [10]="505" [11]="404" [20]="303" [21]="202" [40]="101")
Final Array values
707 606 505 404 303 202 101
Für ältere Bashs müssen Sie eine Schleife (in Bash (seit 2.04)) verwenden und $a
das folgende Leerzeichen verwenden , um das nachfolgende Leerzeichen zu vermeiden:
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a=""
for (( i=last-1 ; i>=0 ; i-- ));do
printf '%s%s' "$a" "${array[i]}"
a=" "
done
echo
Für Bash seit 2.03:
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a="";i=0
while [[ last -ge $((i+=1)) ]]; do
printf '%s%s' "$a" "${array[ last-i ]}"
a=" "
done
echo
Auch (mit dem bitweisen Negationsoperator) (seit Bash 4.2+):
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a=""
for (( i=0 ; i<last ; i++ )); do
printf '%s%s' "$a" "${array[~i]}"
a=" "
done
echo
Hässlich, nicht zu pflegen, aber Einzeiler:
eval eval echo "'\"\${array['{$((${#array[@]}-1))..0}']}\"'"
eval eval echo "'\"\${array[-'{1..${#array[@]}}']}\"'"
.
ind=("${!array[@]}");eval eval echo "'\"\${array[ind[-'{1..${#array[@]}}']]}\"'"
Obwohl ich nichts Neues erzählen werde und auch tac
das Array umkehren werde, wäre es dennoch erwähnenswert, die folgende einzeilige Lösung mit der bash-Version 4.4 zu erwähnen:
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}" |tac)
Testen:
$ array=(1 2 3 4 5 6 10 11 12)
$ echo "${array[@]}"
1 2 3 4 5 6 10 11 12
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}"|tac)
$ echo "${array[@]}"
12 11 10 6 5 4 3 2 1
Beachten Sie, dass der in read enthaltene Variablenname der Name des ursprünglichen Arrays ist, sodass für die temporäre Speicherung kein Hilfsarray erforderlich ist.
Alternative Implementierung durch Anpassung des IFS:
$ IFS=$'\n' read -d '' -a array < <(printf '%s\n' "${array[@]}"|tac);declare -p array
declare -a array=([0]="12" [1]="11" [2]="10" [3]="6" [4]="5" [5]="4" [6]="3" [7]="2" [8]="1")
PS: Ich denke, obige Lösungen funktionieren nicht in der folgenden bash
Version, 4.4
da verschiedene read
Bash-Funktionen implementiert wurden.
IFS
Version funktioniert , aber es ist auch Druck: declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="10" [7]="11" [8]="12")
. Bash benutzen 4.4-5
. Sie haben zu entfernen , ;declare -p array
am Ende der ersten Zeile, dann funktioniert es ...
declare -p
ist nur ein schneller Weg, um bash das echte Array (Index und Inhalt) drucken zu lassen. Sie brauchen diesen declare -p
Befehl nicht in Ihrem echten Skript. Wenn in Ihren Array-Zuweisungen etwas schief geht, kann dies dazu führen, dass ${array[0]}="1 2 3 4 5 6 10 11 12"
= alle Werte im selben Index gespeichert sind - mit Echo werden Sie keinen Unterschied feststellen. Für einen schnellen Array-Ausdruck erhalten declare -p array
Sie mit die tatsächlichen Array-Indices und den entsprechenden Wert in jedem Index.
read -d'\n'
Methode bei dir nicht funktioniert?
read -d'\n'
funktioniert gut.
So kehren Sie ein beliebiges Array um (das beliebig viele Elemente mit beliebigen Werten enthalten kann):
Mit zsh
:
array_reversed=("${(@Oa)array}")
Mit bash
4.4+, da bash
Variablen nicht enthalten NUL - Bytes wie auch immer, Sie GNU verwenden können , tac -s ''
auf die Elemente gedruckt als NUL Datensätze begrenzt:
readarray -td '' array_reversed < <(
((${#array[@]})) && printf '%s\0' "${array[@]}" | tac -s '')
POSIXly, um das POSIX-Shell-Array ( $@
, aus $1
, $2
...) umzukehren :
code='set --'
n=$#
while [ "$n" -gt 0 ]; do
code="$code \"\${$n}\""
n=$((n - 1))
done
eval "$code"
Reine bash Lösung, würde als Einzeiler funktionieren.
$: for (( i=${#array[@]}-1; i>=0; i-- ))
> do rev[${#rev[@]}]=${array[i]}
> done
$: echo "${rev[@]}"
7 6 5 4 3 2 1
rev+=( "${array[i]}" )
scheint einfacher zu sein.
Sie können auch in Betracht ziehen, seq
array=(1 2 3 4 5 6 7)
for i in $(seq $((${#array[@]} - 1)) -1 0); do
echo ${array[$i]}
done
In freebsd können Sie den Inkrement-Parameter -1 weglassen:
for i in $(seq $((${#array[@]} - 1)) 0); do
echo ${array[$i]}
done
array=(1 2 3 4 5 6 7)
echo "${array[@]} " | tac -s ' '
Oder
array=(1 2 3 4 5 6 7)
reverse=$(echo "${array[@]} " | tac -s ' ')
echo ${reverse[@]}
7 6 5 4 3 2 1
$ tac --version
tac (GNU coreutils) 8.28
tac
wurde bereits erwähnt: unix.stackexchange.com/a/412874/260978 , unix.stackexchange.com/a/467924/260978 , unix.stackexchange.com/a/413176/260978