Respostas:
Eu respondi a pergunta como escrita, e esse código reverte a matriz. (Imprimir os elementos na ordem inversa sem reverter a matriz é apenas um forloop que faz a contagem regressiva do último elemento para zero.) Esse é um algoritmo padrão de "troca primeiro e último".
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[@]}"
Funciona para matrizes de comprimento ímpar e par.
Outra abordagem não convencional:
#!/bin/bash
array=(1 2 3 4 5 6 7)
f() { array=("${BASH_ARGV[@]}"); }
shopt -s extdebug
f "${array[@]}"
shopt -u extdebug
echo "${array[@]}"
Resultado:
7 6 5 4 3 2 1
Se extdebugativado, o array BASH_ARGVcontém em uma função todos os parâmetros posicionais na ordem inversa.
Abordagem não convencional (nem tudo pura bash):
se todos os elementos em uma matriz tiverem apenas um caractere (como na pergunta), você poderá usar rev:
echo "${array[@]}" | revde outra forma:
printf '%s\n' "${array[@]}" | tac | tr '\n' ' '; echoe se você pode usar zsh:
echo ${(Oa)array}tac, como o oposto de catmuito bom para lembrar, OBRIGADO!
rev, preciso mencionar que revnão funcionará corretamente para números com dois dígitos. Por exemplo, um elemento da matriz do 12 uso de rev será impresso como 21. Faça uma tentativa ;-) #
Se você realmente deseja o inverso em outra matriz:
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
}
Então:
array=(1 2 3 4)
reverse array foo
echo "${foo[@]}"
Dá:
4 3 2 1
Isso deve tratar corretamente os casos em que um índice de matriz está ausente, digamos que você tenha array=([1]=1 [2]=2 [4]=4), nesse caso, o loop de 0 ao índice mais alto pode adicionar elementos vazios adicionais.
shellcheckimprima dois avisos: array=(1 2 3 4) <-- SC2034: array appears unused. Verify it or export it.e por:echo "${foo[@]}" <-- SC2154: foo is referenced but not assigned.
declareserve a linha.
declare -nparece não funcionar nas versões bash anteriores ao 4.3.
Para trocar as posições da matriz no local (mesmo com matrizes esparsas) (desde o 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[@]}"
Na execução:
./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
Para o bash mais antigo, você precisa usar um loop (no bash (desde 2.04)) e usá-lo $apara evitar o espaço à direita:
#!/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
Para o bash desde a versão 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
Também (usando o operador de negação bit a bit) (desde o 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
Feio, insustentável, mas com uma linha:
eval eval echo "'\"\${array['{$((${#array[@]}-1))..0}']}\"'"
eval eval echo "'\"\${array[-'{1..${#array[@]}}']}\"'".
ind=("${!array[@]}");eval eval echo "'\"\${array[ind[-'{1..${#array[@]}}']]}\"'"
Embora eu não vou contar algo novo e também usarei tacpara reverter a matriz, vale a pena mencionar a solução de linha única abaixo usando a versão 4.4 do bash:
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}" |tac)
Teste:
$ 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
Lembre-se de que o nome var dentro da leitura é o nome da matriz original, portanto, nenhuma matriz auxiliar é necessária para o armazenamento temporário.
Implementação alternativa ajustando o 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: Eu acho que as soluções acima não funcionarão na bashversão abaixo 4.4devido à readimplementação de funções diferentes do bash.
IFSversão funciona, mas ele também está imprimindo: declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="10" [7]="11" [8]="12"). Usando o bash 4.4-5. Você tem que remover ;declare -p arrayno final da primeira linha, em seguida, ele funciona ...
declare -pé apenas uma maneira rápida de fazer com que o bash imprima a matriz real (índice e conteúdo). Você não precisa deste declare -pcomando em seu script real. Se algo der errado nas atribuições de suas matrizes, você poderá terminar em um caso que ${array[0]}="1 2 3 4 5 6 10 11 12"= todos os valores armazenados no mesmo índice - usando eco, você não verá nenhuma diferença. Para uma impressão rápida da matriz declare -p array, você retornará os indeces reais da matriz e o valor correspondente em cada índice.
read -d'\n'método não funcionou para você?
read -d'\n'funciona bem.
Para reverter uma matriz arbitrária (que pode conter qualquer número de elementos com quaisquer valores):
Com zsh:
array_reversed=("${(@Oa)array}")
Com o bash4.4+, como as bashvariáveis não podem conter bytes NUL, você pode usar o GNU tac -s ''nos elementos impressos como registros delimitados por NUL:
readarray -td '' array_reversed < <(
((${#array[@]})) && printf '%s\0' "${array[@]}" | tac -s '')
POSIXly, para reverter a matriz do shell POSIX ( $@, feita de $1, $2...):
code='set --'
n=$#
while [ "$n" -gt 0 ]; do
code="$code \"\${$n}\""
n=$((n - 1))
done
eval "$code"
Solução de bash pura, funcionaria como uma linha.
$: 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]}" )parece mais simples.
você também pode considerar usar seq
array=(1 2 3 4 5 6 7)
for i in $(seq $((${#array[@]} - 1)) -1 0); do
echo ${array[$i]}
done
no freebsd, você pode omitir -1 parâmetro de incremento:
for i in $(seq $((${#array[@]} - 1)) 0); do
echo ${array[$i]}
done
array=(1 2 3 4 5 6 7)
echo "${array[@]} " | tac -s ' '
Ou
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
tacjá foi mencionado: unix.stackexchange.com/a/412874/260978 , unix.stackexchange.com/a/467924/260978 , unix.stackexchange.com/a/413176/260978