Captura de salida de línea múltiple en una variable Bash

Tengo un script ‘myscript’ que da como resultado lo siguiente:

abc def ghi 

en otro script, llamo:

 declare RESULT=$(./myscript) 

y $RESULT obtiene el valor

 abc def ghi 

¿Hay alguna forma de almacenar el resultado ya sea con las líneas nuevas o con el carácter ‘\ n’ para que pueda mostrarlo con ‘ echo -e ‘?

En realidad, RESULTADO contiene lo que desea, para demostrar:

 echo "$RESULT" 

Lo que muestra es de lo que obtiene:

 echo $RESULT 

Como se señala en los comentarios, la diferencia es que (1) la versión de doble cita de la variable ( echo "$RESULT" ) conserva el espaciado interno del valor exactamente como se representa en la variable: nuevas líneas, tabs, espacios en blanco múltiples y all – mientras que (2) la versión sin comillas ( echo $RESULT ) reemplaza cada secuencia de uno o más espacios en blanco, tabs y nuevas líneas con un solo espacio. Así, (1) conserva la forma de la variable de entrada, mientras que (2) crea una línea de salida única potencialmente larga con ‘palabras’ separadas por espacios únicos (donde una ‘palabra’ es una secuencia de caracteres que no son de espacio en blanco; no hay ningún alfanumérico en ninguna de las palabras).

Otro inconveniente con esto es que la sustitución de comando – $() – elimina las nuevas líneas finales. Probablemente no siempre sea importante, pero si realmente quiere preservar exactamente lo que salió, tendrá que usar otra línea y algunas citas:

 RESULTX="$(./myscript; echo x)" RESULT="${RESULTX%x}" 

Esto es especialmente importante si desea manejar todos los nombres de archivo posibles (para evitar el comportamiento indefinido, como operar en el archivo incorrecto).

Además de la respuesta dada por @ l0b0, tuve la situación en la que necesitaba mantener las líneas nuevas producidas por el script y verificar el código de retorno del script. ¿Y el problema con la respuesta de l0b0 es que el ‘eco x’ estaba reiniciando $? de vuelta a cero … así que logré encontrar esta solución tan astuta:

 RESULTX="$(./myscript; echo x$?)" RETURNCODE=${RESULTX##*x} RESULT="${RESULTX%x*}" 

En caso de que esté interesado en líneas específicas, use una matriz de resultados:

 declare RESULT=($(./myscript)) # (..) = array echo "First line: ${RESULT[0]}" echo "Second line: ${RESULT[1]}" echo "N-th line: ${RESULT[N]}" 

¿Qué tal esto, leerá cada línea a una variable y que se puede utilizar posteriormente! decir que la salida de myscript se redirige a un archivo llamado myscript_output

 awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}' 

Después de probar la mayoría de las soluciones aquí, lo más fácil que encontré fue lo obvio: usar un archivo temporal. No estoy seguro de qué quiere hacer con su salida de línea múltiple, pero puede tratarlo línea por línea usando leer. Lo único que realmente no se puede hacer es pegar fácilmente todo en la misma variable, pero para la mayoría de los propósitos prácticos es más fácil lidiar con esto.

 ./myscript.sh > /tmp/foo while read line ; do echo 'whatever you want to do with $line' done < /tmp/foo 

Quick hack para que haga la acción solicitada:

 result="" ./myscript.sh > /tmp/foo while read line ; do result="$result$line\n" done < /tmp/foo echo -e $result 

Tenga en cuenta que esto agrega una línea adicional. Si trabajas en él puedes codificarlo, soy demasiado flojo.


EDITAR: Aunque este caso funciona perfectamente, las personas que lo lean deben ser conscientes de que puedes aplastar fácilmente tu stdin dentro del ciclo while, lo que te dará un script que ejecutará una línea, borrará stdin y saldrá. Al igual que ssh hará eso, creo? Acabo de verlo recientemente, otros ejemplos de código aquí: https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while

¡Una vez más! Esta vez con un identificador de archivo diferente (stdin, stdout, stderr son 0-2, entonces podemos usar & 3 o más en bash).

 result="" ./test>/tmp/foo while read line <&3; do result="$result$line\n" done 3 

también puedes usar mktemp, pero este es solo un ejemplo de código rápido. El uso para mktemp es similar a:

 filenamevar=`mktemp /tmp/tempXXXXXX` ./test > $filenamevar 

Luego use $ filenamevar como lo haría con el nombre real de un archivo. Probablemente no necesite ser explicado aquí, pero alguien se quejó en los comentarios.