Invertir el contenido de una variable por palabras

Invertir el contenido de una variable por palabras

Entonces si tengo una variable

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

y resuélvelo

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

Sin embargo, más abajo en el script necesito invertir el orden de esta variable para que se muestre como algo así como

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

Intenté usar rev y literalmente invirtió todo, por lo que salió como

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

Respuesta1

En los sistemas GNU, el reverso de cat es tac:

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

Respuesta2

Para una lista corta, y en una variable, el propio shell es la solución más 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

Producción:

100 90 80 70 60 50 40 30 20 10 

Nota: la operación de división set -- $vares segura para la cadena exacta utilizada aquí, pero no lo será si la cadena contiene caracteres comodín ( *o ?) []. Puede evitarse set -fantes de la división, si es necesario. La misma nota también es válida para las siguientes soluciones (excepto donde se indique lo contrario).

O, si desea configurar alguna otra variable con la 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"

O usando solo los parámetros posicionales.

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"

O usar solo una variable (que puede ser la propia var):
Nota: Esta solución no se ve afectada por globing ni IFS.

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

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

Respuesta3

awkal rescate

$ 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


con perlcortesía¿Cómo leer una dirección IP al revés?compartido por @steeldriver

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


O consigo bashmismo convirtiendo la cadena en una matriz

$ 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 

Respuesta4

zsh:

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

$=VARse divide $VARen $IFS. (Oa)ordena la lista resultante en orden inverso. print -r --(como en ksh), igual que echo -E -( zshespecífico) esversiones confiables deecho: imprime sus argumentos tal cual, separados por espacios, terminados por una nueva línea.

Si desea dividir solo en el espacio, y no en lo que $IFScontiene (espacio, tabulación, nueva línea, nulo de forma predeterminada), asigne espacio $IFSo use una división explícita como:

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

Para ordenar en orden numérico inverso:

$ 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 (también funcionaría con bash):

Solo con mecanismos integrados en el shell (excepto printfen algunos shells) (mejor para variables con un valor corto):

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"

Con awk(mejor para variables grandes, especialmente con bash, pero hasta el límite del tamaño de los argumentos (o de un solo argumento)):

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

información relacionada