with variable simple pipes exercises examples example define linux bash pipe

linux - variable - Escritura bash, valores de lectura de stdin pipe



pipes in linux with examples (15)

Aquí hay una solución alternativa, que también se puede usar al leer más de una variable y cuando hay más palabras en el tubo que el número de variables que se leen.

eval $(echo hickery dickery dock the mouse | { read A B C ; echo A=/"${A}/" B=/"${B}/" C=/"${C}/" ; }) echo $A hickery echo $B dickery echo $C dock the mouse

Estoy intentando que bash procese los datos de stdin que se canalizan, pero no hay suerte, lo que quiero decir es que ninguno de los siguientes trabajos:

echo "hello world" | test=($(< /dev/stdin)); echo test=$test test= echo "hello world" | read test; echo test=$test test= echo "hello world" | test=`cat`; echo test=$test test=

donde quiero que la salida sea test=hello world . Tenga en cuenta que he intentado poner "" comillas alrededor de "$test" que tampoco funciona.


Creo que estabas tratando de escribir un script de shell que podría tomar la entrada de stdin. pero mientras intentas hacerlo en línea, te perdiste tratando de crear esa prueba = variable. Creo que no tiene mucho sentido hacerlo en línea, y es por eso que no funciona de la manera esperada.

Estaba tratando de reducir

$( ... | head -n $X | tail -n 1 )

para obtener una línea específica de varias entradas. entonces podría escribir ...

cat program_file.c | line 34

entonces necesito un pequeño programa shell capaz de leer de stdin. como tu lo haces.

22:14 ~ $ cat ~/bin/line #!/bin/sh if [ $# -ne 1 ]; then echo enter a line number to display; exit; fi cat | head -n $1 | tail -n 1 22:16 ~ $

ahí tienes.


El primer intento fue bastante cercano. Esta variación debería funcionar:

echo "hello world" | { test=$(< /dev/stdin); echo "test=$test"; };

y el resultado es:

prueba = hola mundo

Necesitas llaves después de la tubería para adjuntar la tarea para probar y el eco.

Sin las llaves, la tarea de probar (después de la tubería) está en un shell, y el eco "test = $ test" está en un shell separado que no sabe acerca de esa asignación. Es por eso que estaba obteniendo "test =" en la salida en lugar de "test = hello world".


El siguiente código:

echo "hello world" | ( test=($(< /dev/stdin)); echo test=$test )

también funcionará, pero abrirá otro nuevo subconjunto después del conducto, donde

echo "hello world" | { test=($(< /dev/stdin)); echo test=$test; }

no lo hará

Tuve que desactivar el control de trabajo para hacer uso del método de chepnars (estaba ejecutando este comando desde la terminal):

set +m;shopt -s lastpipe echo "hello world" | read test; echo test=$test echo "hello world" | test="$(</dev/stdin)"; echo test=$test

Bash Manual dice :

último tubo

Si se establece, y el control del trabajo no está activo , el shell ejecuta el último comando de una tubería no ejecutada en segundo plano en el entorno de shell actual.

Nota: el control del trabajo está desactivado de forma predeterminada en un shell no interactivo y, por lo tanto, no necesita el set +m dentro de un script.


En mi opinión, la mejor manera de leer de stdin in bash es la siguiente, que también te permite trabajar en las líneas antes de que finalice la entrada:

while read LINE; do echo $LINE done < /dev/stdin


Esta es otra opción

$ read test < <(echo hello world) $ echo $test hello world


La sintaxis para un conducto implícito de un comando de shell en una variable bash es

var=$(command)

o

var=`command`

En los ejemplos, está conectando datos a una declaración de asignación, que no espera ninguna entrada.


No soy un experto en Bash, pero me pregunto por qué no se ha propuesto esto:

stdin=$(cat) echo "$stdin"

Prueba de un trazador de líneas que funciona para mí:

$ fortune | eval ''stdin=$(cat); echo "$stdin"''


Porque me enamoro de eso, me gustaría dejar caer una nota. Encontré este hilo, porque tengo que reescribir un antiguo script sh para que sea compatible con POSIX. Esto básicamente significa evitar el problema de la tubería / subshell introducido por POSIX al reescribir un código como este:

some_command | read a b c

dentro:

read a b c << EOF $(some_command) EOF

Y codifique así:

some_command | while read a b c; do # something done

dentro:

while read a b c; do # something done << EOF $(some_command) EOF

Pero este último no se comporta de la misma manera en la entrada vacía. Con la notación antigua, el ciclo while no se ingresa en la entrada vacía, ¡pero sí en la notación POSIX! Creo que se debe a la nueva línea antes de EOF, que no se puede omitir. El código POSIX que se comporta más como la notación antigua se ve así:

while read a b c; do case $a in ("") break; esac # something done << EOF $(some_command) EOF

En la mayoría de los casos, esto debería ser lo suficientemente bueno. Pero desafortunadamente esto todavía no se comporta exactamente como la notación anterior si some_command imprime una línea vacía. En la vieja notación, el cuerpo while se ejecuta y en notación POSIX nos rompemos frente al cuerpo.

Un enfoque para solucionar esto podría verse así:

while read a b c; do case $a in ("something_guaranteed_not_to_be_printed_by_some_command") break; esac # something done << EOF $(some_command) echo "something_guaranteed_not_to_be_printed_by_some_command" EOF


Qué tal esto:

echo "hello world" | echo test=$(cat)


Tirar algo en una expresión que involucra una tarea no se comporta de esa manera.

En cambio, intente:

test=$(echo "hello world"); echo test=$test


Utilizar

IFS= read var << EOF $(foo) EOF

Puede engañar a la read para que acepte de una tubería como esta:

echo "hello world" | { read test; echo test=$test; }

o incluso escribir una función como esta:

read_from_pipe() { read "$@" <&0; }

Pero no tiene sentido, ¡sus asignaciones variables pueden no durar! Una canalización puede engendrar una subshell, donde el entorno se hereda por valor, no por referencia. Esta es la razón por la cual la read no molesta con la entrada de una tubería; no está definida.

FYI, http://www.etalabs.net/sh_tricks.html es una colección ingeniosa de los restos necesarios para luchar contra las rarezas e incompatibilidades de las conchas bourne, sh.


si desea leer muchos datos y trabajar en cada línea por separado, podría usar algo como esto:

cat myFile | while read x ; do echo $x ; done

si quiere dividir las líneas en múltiples palabras, puede usar múltiples variables en lugar de x como esta:

cat myFile | while read x y ; do echo $y $x ; done

alternativamente:

while read x y ; do echo $y $x ; done < myFile

Pero tan pronto como comiences a querer hacer algo realmente inteligente con este tipo de cosas, es mejor que vayas a un lenguaje de scripting como Perl, donde podrías probar algo como esto:

perl -ane ''print "$F[0]/n"'' < myFile

Hay una curva de aprendizaje bastante empinada con Perl (o supongo que en cualquiera de estos idiomas) pero a la larga te resultará mucho más fácil si quieres hacer algo más que los scripts más sencillos. Recomendaría el Perl Cookbook y, por supuesto, el lenguaje de programación Perl de Larry Wall et al.


bash 4.2 introduce la opción lastpipe , que permite que tu código funcione tal como está escrito, ejecutando el último comando en una canalización en el shell actual, en lugar de una subshell.

shopt -s lastpipe echo "hello world" | read test; echo test=$test


read no leerá desde una tubería (o posiblemente se pierda el resultado porque la tubería crea una subcamada). Sin embargo, puedes usar una cadena aquí en Bash:

$ read a b c <<< $(echo 1 2 3) $ echo $a $b $c 1 2 3