2009-03-05 28 views
418

Tengo un script 'miscript' que emite la siguiente:Captura de la salida de varias líneas en una variable Bash

abc 
def 
ghi 

en otro guión, me llaman:

declare RESULT=$(./myscript) 

y tiene la $RESULT valor

abc def ghi 

Hay una manera de almacenar el resultado ya sea con las líneas nuevas, o con el carácter '\ n', así que c una salida con 'echo -e'?

+1

me sorprende. ¿no tienes $ (cat ./myscipt)? de lo contrario, habría esperado que intentara ejecutar comandos abc, def y ghi –

+0

@litb: sí, supongo que sí; también puede usar $ (<./ myscript) que evita ejecutar un comando. –

+2

(NB: los dos comentarios anteriores se refieren a una revisión de la pregunta que comenzó _Tengo un script 'myscript' que contiene lo siguiente_, lo que llevó a las preguntas. La revisión actual de la pregunta (_Tengo un guión) 'myscript' que da como resultado lo siguiente_) hace que los comentarios sean superfluos. Sin embargo, la revisión es de 2011-11-11, mucho después de que se hicieron los dos comentarios. –

Respuesta

784

En realidad, resultado contiene lo que quiere - para demostrar:

echo "$RESULT" 

lo que muestran es lo que se obtiene a partir de:

echo $RESULT 

Como se señaló en los comentarios, la diferencia es que (1) la versión de cotización doble de la variable (echo "$RESULT") conserva el espaciado interno del valor exactamente como se representa en la variable - nuevas líneas, pestañas, espacios en blanco múltiples y all - wherea s (2) la versión sin comillas (echo $RESULT) reemplaza cada secuencia de uno o más espacios en blanco, pestañas y líneas nuevas 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).

+59

@troelskn: la diferencia es que (1) la versión de doble cita de la variable conserva el espaciado interno del valor exactamente como se representa en la variable, nuevas líneas, pestañas, espacios en blanco múltiples y todo, mientras que (2) la versión sin comillas reemplaza cada secuencia de uno o más espacios en blanco, pestañas y líneas nuevas 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éricos en cualquiera de las palabras). –

+17

Para que la respuesta sea más fácil de entender: la respuesta dice que el eco "$ RESULT" conserva la línea nueva, mientras que echo $ RESULT no lo hace. –

+0

Esto no conserva líneas nuevas y espacios iniciales en algunas situaciones. – CommaToast

72

Otra trampa con esto es que command substitution - $() - tiras de líneas nuevas. Probablemente no es siempre importante, pero si realmente desea conservar exactamente lo que estaba de salida, que tendrá que utilizar otra línea y algunos citar:

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

Esto es especialmente importante si se quiere handle all possible filenames (para evitar comportamiento indefinido como operar en el archivo incorrecto).

+3

+1 Esto es cierto y ¡Lo que faltaba en la respuesta de JonathanLeffler! –

+3

Tuve que trabajar por un tiempo con un shell roto que no eliminó la última línea nueva de la [sustitución del comando] (http://www.gnu.org/software/bash/manual/bash.html#Command-Substitution) (es _no_ [sustitución de proceso] (http://www.gnu.org/software/bash/manual/bash.html#Process-Substitution)), y rompió casi todo. Por ejemplo, si hiciste '' pwd = 'pwd'; ls $ pwd/$ file'', obtuviste una nueva línea antes del '/', y adjuntar el nombre entre comillas dobles no ayudó. Fue reparado rápidamente. Esto fue en 1983-5 marco de tiempo en ICL Perq PNX; el shell no tenía '$ PWD' como una variable incorporada. –

0

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

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

Bueno, eso no es bash, eso es awk. – vadipp

12

Además de la respuesta dada por @ l0b0 sólo tenía la situación en la que necesitaba tanto mantener ningún tipo de salida de las nuevas líneas de ir perdiendo por el guión y verificación de la código de retorno del script ¿Y el problema con la respuesta de l0b0 es que el 'eco x' estaba reiniciando $? de nuevo a cero ... así que me las arreglé para llegar a esta solución muy astuto:

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

En caso de que usted está interesado en líneas específicas, usar un resultado de matriz:

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

Si hay espacios en las líneas, esto contará los campos (contenidos entre espacios) en lugar de líneas. – Liam

+3

esto no funciona en Dash o shell POSIX – gpanda

+1

Usted usaría 'readarray' y la sustitución de procesos en lugar de la sustitución de comandos:' readarray -t RESULTADO <<(./myscript> '. – chepner

0

Después probando 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 

truco rápido para que hiciera la acción solicitada:

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

Nota esto añade una línea adicional. Si trabajas en él puedes codificarlo, soy demasiado flojo.


EDIT: Si bien este caso funciona perfectamente bien, la gente que lee esto debe ser consciente de que puede aplastar fácilmente su entrada estándar en el interior del bucle while, lo que te da un script que se ejecutará una línea, la entrada estándar clara, y la salida . 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 superior en bash).

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

También puede usar mktemp, pero este es solo un ejemplo de código rápido. Uso de mktemp parece:

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

A continuación, utilice $ 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.

+0

Probé otras soluciones también, con su primera sugerencia finalmente conseguí que mi script funcionara –

+1

Voto a la baja: Esto es excesivamente complejo, y no evita múltiples errores comunes ['bash'] (http://mywiki.wooledge.org/BashPitfalls) . – tripleee

+0

Ya alguien me contó sobre el extraño problema del manejo de archivos stdin el otro día y yo estaba como "guau". Déjame agregar algo realmente rápido. – user1279741

Cuestiones relacionadas