¿Cómo leer la entrada multilínea de la entrada estándar en una variable y cómo imprimir una en Shell (sh, bash)?
Pregunta
Lo que quiero hacer es lo siguiente:
- leer en entrada de varias líneas desde
stdin
en variableA
- realizar diversas operaciones en
A
- tubo
A
sin perder los símbolos delimitadores (\n
,\r
,\t
,etc) a otro comando
El problema actual es que no puedo leerlo con read
comando, porque deja de leer en una nueva línea.
Puedo leer stdin con cat
, como esto:
my_var=`cat /dev/stdin`
, pero luego no sé cómo imprimirlo.De modo que la nueva línea, la tabulación y otros delimitadores sigan ahí.
Mi script de muestra se ve así:
#!/usr/local/bin/bash
A=`cat /dev/stdin`
if [ ${#A} -eq 0 ]; then
exit 0
else
cat ${A} | /usr/local/sbin/nextcommand
fi
Solución
Esto está funcionando para mí:
myvar=`cat`
echo "$myvar"
Las citas alrededor de $myvar
son importantes.
Otros consejos
En Bash, hay una forma alternativa; man bash
menciona:
La sustitución del comando
$(cat file)
se puede reemplazar por el equivalente pero más rápido$(< file)
.
$ myVar=$(</dev/stdin)
hello
this is test
$ echo "$myVar"
hello
this is test
tee hace el trabajo
#!/bin/bash
myVar=$(tee)
Sí, a mí también me funciona. Gracias.
myvar=`cat`
es lo mismo que
myvar=`cat /dev/stdin`
Bueno, sí. Desde la página de manual de bash
:
Encerrar caracteres entre comillas dobles conserva el valor literal de todos personajes dentro de las comillas, con la excepción de $, `, \ y cuando la expansión del historial es habilitado,!. Los caracteres $ y ` retener su significado especial entre comillas dobles.
Si le interesa preservar las nuevas líneas al final de la salida, use esto:
myVar=$(cat; echo x)
myVar=${myVar%x}
printf %s "$myVar"
Esto utiliza el truco de aquí .
.[actualizado]
Esta tarea se bloqueará indefinidamente si no hay nada en la tubería...
var="$(< /dev/stdin)"
Sin embargo, podemos evitar esto haciendo un tiempo de espera. read
para el primer personaje.Si se agota el tiempo de espera, el código de retorno será mayor que 128 y conoceremos la tubería STDIN (también conocida como /dev/stdin
) esta vacio.
De lo contrario, obtenemos el resto de STDIN por...
- configuración
IFS
a NULL solo para elread
dominio - apagando escapes con
-r
- eliminando el delimitador de lectura con
-d ''
. - y finalmente, agregar eso al personaje que obtuvimos inicialmente.
De este modo...
__=""
_stdin=""
read -N1 -t1 __ && {
(( $? <= 128 )) && {
IFS= read -rd '' _stdin
_stdin="$__$_stdin"
}
}
Esta técnica evita el uso var="$(command ...)"
Sustitución de comando que, por diseño, siempre eliminará las nuevas líneas finales.
Si se prefiere la sustitución de comandos, para preservar las nuevas líneas finales podemos agregar uno o más caracteres delimitadores a la salida dentro del $()
y luego quítelos afuera.
Por ejemplo ( nota $(parens)
en el primer comando y ${braces}
en segundo )...
_stdin="$(awk '{print}; END {print "|||"}' /dev/stdin)"
_stdin="${_stdin%|||}"