world scripts script hello example ejemplos basics linux bash shell ksh dash

scripts - script bash linux ejemplos



Shell scripting input redirection rarezas (9)

Esto ya se ha respondido correctamente, pero la solución aún no se ha establecido. Usa ksh, no bash. Comparar:

$ echo ''echo "hello world" | read var1 var2 echo $var1 echo $var2'' | bash -s

A:

$ echo ''echo "hello world" | read var1 var2 echo $var1 echo $var2'' | ksh -s hello world

ksh es un shell de programación superior debido a pequeñas sutilezas como esta. (Bash es el mejor intérprete interactivo, en mi opinión).

¿Alguien puede explicar este comportamiento? Corriendo:

#!/bin/sh echo "hello world" | read var1 var2 echo $var1 echo $var2

da como resultado que no se produzca nada, mientras:

#!/bin/sh echo "hello world" > test.file read var1 var2 < test.file echo $var1 echo $var2

produce el resultado esperado:

hello world

¿No debería el tubo hacer en un solo paso lo que hizo la redirección al archivo de prueba en el segundo ejemplo? Probé el mismo código tanto con el tablero como con el bash y obtuve el mismo comportamiento en ambos.


Se debe a que la versión de tubería está creando una subcadena, que lee la variable en su espacio local, que luego se destruye cuando la subshell se cierra.

Ejecuta este comando

$ echo $$;cat | read a 10637

y use pstree -p para observar los procesos en ejecución, verá una capa adicional colgando de su caparazón principal.

| |-bash(10637)-+-bash(10786) | | `-cat(10785)


La publicación se ha respondido correctamente, pero me gustaría ofrecer una línea alternativa que quizás podría ser de alguna utilidad.

Para asignar valores separados por espacio de echo (o stdout para el caso) a variables de shell, podría considerar usar matrices de shell:

$ var=( $( echo ''hello world'' ) ) $ echo ${var[0]} hello $ echo ${var[1]} world

En este ejemplo, var es una matriz y se puede acceder a los contenidos utilizando la construcción $ {var [index]}, donde index es el índice de la matriz (comienza con 0).

De esta forma, puede tener tantos parámetros como desee asignados al índice de matriz relevante.


Tratar:

echo "hello world" | (read var1 var2 ; echo $var1 ; echo $var2 )

El problema, como han afirmado varias personas, es que var1 y var2 se crean en un entorno subshell que se destruye cuando se cierra esa subcapa. Lo anterior evita la destrucción de la subcapa hasta que el resultado haya sido eco. Otra solución es:

result=`echo "hello world"` read var1 var2 <<EOF $result EOF echo $var1 echo $var2


#!/bin/sh echo "hello world" | read var1 var2 echo $var1 echo $var2

no produce salida porque las tuberías ejecutan cada uno de sus componentes dentro de una subcadena. Las subcadenas heredan copias de las variables del shell principal, en lugar de compartirlas. Prueba esto:

#!/bin/sh foo="contents of shell variable foo" echo $foo ( echo $foo foo="foo contents modified" echo $foo ) echo $foo

Los paréntesis definen una región de código que se ejecuta en una subshell, y $ foo conserva su valor original después de ser modificado dentro de ellos.

Ahora prueba esto:

#!/bin/sh foo="contents of shell variable foo" echo $foo { echo $foo foo="foo contents modified" echo $foo } echo $foo

Los refuerzos son puramente para agrupar, no se crea una subescala, y el $ foo modificado dentro de las llaves es el mismo $ foo modificado fuera de ellos.

Ahora prueba esto:

#!/bin/sh echo "hello world" | { read var1 var2 echo $var1 echo $var2 } echo $var1 echo $var2

Dentro de los corchetes, el builtin de lectura crea $ var1 y $ var2 correctamente y se puede ver que se hacen eco. Fuera de las llaves, ya no existen. Todo el código dentro de las llaves se ha ejecutado en una subcapa porque es un componente de una tubería .

Puede poner cantidades arbitrarias de código entre llaves, para que pueda usar esta construcción de tubería en un bloque cada vez que necesite ejecutar un bloque de script de shell que analiza el resultado de otra cosa.


Mi opinión sobre este tema (usando Bash):

read var1 var2 <<< "hello world" echo $var1 $var2


read var1 var2 < <(echo "hello world")


Una adición reciente a bash es la opción lastpipe , que permite que el último comando de una canalización se ejecute en el shell actual, no en una subcapa, cuando el control de tareas está desactivado.

#!/bin/bash set +m # Deactiveate job control shopt -s lastpipe echo "hello world" | read var1 var2 echo $var1 echo $var2

de hecho saldrá

hello world


¡Bien, lo descubrí!

Este es un error difícil de capturar, pero resulta de la forma en que el caparazón maneja las tuberías. Cada elemento de una tubería se ejecuta en un proceso separado. Cuando el comando de lectura establece var1 y var2, se establece su propia subshell, no el shell principal. Entonces, cuando la subshell sale, los valores de var1 y var2 se pierden. Sin embargo, puedes intentar hacer

var1=$(echo "Hello") echo var1

que devuelve la respuesta esperada. Desafortunadamente, esto solo funciona para variables individuales, no puede establecer muchas a la vez. Para establecer múltiples variables a la vez, debe leer en una variable y dividirla en múltiples variables o usar algo como esto:

set -- $(echo "Hello World") var1="$1" var2="$2" echo $var1 echo $var2

Aunque admito que no es tan elegante como usar una pipa, funciona. Por supuesto, debe tener en cuenta que la lectura debe leer los archivos en variables, por lo que leer desde la entrada estándar debería ser un poco más difícil.