¿Cómo leer la entrada de mutlilina de stdin en variable y cómo imprimir una en shell(sh,bash)?


Lo que quiero hacer es lo siguiente: {[12]]}

  1. leer en entrada de línea múltiple desde stdin en variable A
  2. hacer varias operaciones en A
  3. pipe A sin perder símbolos delimitadores(\n,\r,\t,etc) a otro comando

El problema actual es que, no puedo leerlo con el comando read, porque deja de leer en nueva línea.

Puedo leer stdin con cat, así:

my_var=`cat /dev/stdin`

, pero entonces no se como para imprimirlo. Para que la nueva línea, la pestaña y otros delimitadores sigan ahí.

Mi script de ejemplo 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
Author: xpda, 2008-10-17

6 answers

Esto está funcionando para mí:

myvar=`cat`

echo "$myvar"

Las citas alrededor de $myvar son importantes.

 51
Author: Tanktalus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-01 09:15:53

En Bash, hay una forma alternativa; man bash menciona:

El comando substitution $(cat file) puede ser reemplazado por el equivalente pero más rápido $(< file).

$ myVar=$(</dev/stdin)
hello
this is test
$ echo "$myVar"
hello
this is test
 18
Author: Ingo Karkat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-07 10:47:31

Tee hace el trabajo

#!/bin/bash
myVar=$(tee)
 7
Author: Sergey Grigoriev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-27 09:33:47

Sí funciona para mí también. Gracias.

myvar=`cat`

Es lo mismo que

myvar=`cat /dev/stdin`

Bueno, sí. De la página de manual de bash:

Encerrar caracteres entre comillas dobles conserva el valor literal de todos caracteres dentro de las comillas, con la excepción de$,',\, y, cuando la expansión de la historia es habilitado !. Los personajes and y ` conserve su significado especial entre comillas dobles.

 6
Author: leemes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-11 13:27:03

Si te importa conservar las nuevas líneas finales al final de la salida, usa esto:

myVar=$(cat; echo x)
myVar=${myVar%x}
printf %s "$myVar"

Esto usa el truco de aquí.

 3
Author: Ingo Karkat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-09 07:01:01

[actualizado]

Esta asignación se colgará indefinidamente si no hay nada en la tubería...

var="$(< /dev/stdin)"

Podemos evitar esto haciendo un tiempo de espera read para el primer carácter. Si se agota el tiempo, el código de retorno será mayor que 128 y sabremos que la tubería STDIN (también conocida como /dev/stdin) está vacía.

De lo contrario, obtenemos el resto de STDIN por...

  • estableciendo IFS a NULL solo para el comando read
  • desactivando los escapes con -r
  • eliminando el delimitador de lectura con -d ''.
  • y finalmente, añadiendo eso al carácter que obtuvimos inicialmente

Así...

__=""
_stdin=""

read -N1 -t1 __  && {
  (( $? <= 128 ))  && {
    IFS= read -rd '' _stdin
    _stdin="$__$_stdin"
  }
}

Esta técnica evita usar var="$(command ...)" Sustitución de comandos que, por diseño, siempre eliminará cualquier nueva línea final.

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 eliminarlos fuera.

Por ejemplo (nota $(parens) en el primer comando y ${braces} en el segundo )...

_stdin="$(awk '{print}; END {print "|||"}' /dev/stdin)"
_stdin="${_stdin%|||}"
 1
Author: DocSalvager,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-01 12:35:03