Invertendo o conteúdo de uma variável por palavras

Invertendo o conteúdo de uma variável por palavras

Então, se eu tiver uma variável

VAR='10 20 30 40 50 60 70 80 90 100'

e ecoar

echo "$VAR"
10 20 30 40 50 60 70 80 90 100

Porém, mais abaixo no script eu preciso reverter a ordem dessa variável para que ela apareça como algo como

echo "$VAR" | <code to reverse it>
100 90 80 70 60 50 40 30 20 10

Eu tentei usar rev e literalmente inverteu tudo, então saiu como

echo "$VAR" | rev
001 09 08 07 06 05 04 03 02 01

Responder1

Em sistemas GNU, o inverso de cat é tac:

$ tac -s" " <<< "$VAR "            # Please note the added final space.
100 90 80 70 60 50 40 30 20 10

Responder2

Para uma lista curta e em uma variável, o próprio shell é a solução mais rápida:

var="10 20 30 40 50 60 70 80 90 100"
set -- $var; unset a 
for ((i=$#;i>0;i--)); do
    printf '%s%s' "${a:+ }" "${!i}"
    a=1
done
echo

Saída:

100 90 80 70 60 50 40 30 20 10 

Nota: a operação de divisão set -- $varé segura para a string exata usada aqui, mas não será se a string contiver caracteres curinga ( *, ?ou []). Pode ser evitado set -fantes da divisão, se necessário. A mesma nota também é válida para as seguintes soluções (exceto onde indicado).

Ou, se você quiser definir alguma outra variável com a lista inversa:

var="10 20 30 40 50 60 70 80 90 100"
set -- $var
for i; do out="$i${out:+ }$out"; done
echo "$out"

Ou usando apenas os parâmetros posicionais.

var="10 20 30 40 50 60 70 80 90 100"
set -- $var
a=''
for    i
do     set -- "$i${a:+ $@}"
       a=1
done
echo "$1"

Ou usando apenas uma variável (que pode ser a própria var):
Nota: Esta solução não é afetada pelo globing nem pelo IFS.

var="10 20 30 40 50 60 70 80 90 100"

a=" $var"
while [[ $a ]]; do
    printf '<%s>' "${a##* }"
    var="${a% *}"
done

Responder3

awkpara o resgate

$ var='10 20 30 40 50 60 70 80 90 100'

$ echo "$var" | awk '{for(i=NF; i>0; i--) printf i==1 ? $i"\n" : $i" "}'
100 90 80 70 60 50 40 30 20 10


com perl, cortesiaComo ler um endereço IP de trás para frente?compartilhado por @steeldriver

$ echo "$var" | perl -lane '$,=" "; print reverse @F'
100 90 80 70 60 50 40 30 20 10


Ou, consigo bashmesmo, convertendo a string em array

$ arr=($var)    
$ for ((i=${#arr[@]}-1; i>=0; i--)); do printf "${arr[i]} "; done; echo
100 90 80 70 60 50 40 30 20 10 

Responder4

zsh:

print -r -- ${(Oa)=VAR}

$=VARse divide $VARem $IFS. (Oa)ordena a lista resultante na ordem inversa da matriz. print -r --(como em ksh), o mesmo que echo -E -(zsh específico) éversões confiáveis ​​deecho: imprime seus argumentos como estão separados por espaço, finalizados por nova linha.

Se você deseja dividir apenas no espaço, e não no que $IFScontém (espaço, tabulação, nova linha, nulo por padrão), atribua espaço a $IFSou use uma divisão explícita como:

print -r -- ${(Oas: :)VAR}

Para classificar em ordem numérica inversa:

$ VAR='50 10 20 90 100 30 60 40 70 80'
$ print -r -- ${(nOn)=VAR}
100 90 80 70 60 50 40 30 20 10

POSIXly (também funcionaria com bash):

Apenas com mecanismos internos do shell (exceto printfem alguns shells) (melhor para variáveis ​​com um valor curto):

unset -v IFS # restore IFS to its default value of spc, tab, nl
set -o noglob # disable glob
set -- $VAR # use the split+glob operator to assign the words to $1, $2...

reversed_VAR= sep=
for i do
  reversed_VAR=$i$sep$reversed_VAR
  sep=' '
done
printf '%s\n' "$reversed_VAR"

With awk(melhor para variáveis ​​grandes, especialmente with bash, mas até o limite do tamanho dos argumentos (ou de um único argumento)):

 awk '
   BEGIN {
     n = split(ARGV[1], a);
     while (n) {printf "%s", sep a[n--]; sep = " "}
     print ""
   }' "$VAR"

informação relacionada