Estoy tratando de conseguir bash para procesar datos desde la entrada estándar stdin que consigue canalizar, pero no hubo 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 test=hello world. He intentado poner «» comillas alrededor de "$test" que no funciona bien.

  • Su ejemplo.. echo «hola mundo» | lectura de la prueba; prueba de eco=$prueba funcionó bien para mí.. resultado: prueba=hola mundo ; ¿qué ambiente se están ejecutando este bajo? Estoy usando bash 4.2..
  • ¿Quieres varias líneas en una sola lectura? Su ejemplo muestra sólo una línea, pero la descripción del problema es claro.
  • Estoy ejecutando Bash versión 4.2.25, y su ejemplo no me funciona demasiado. Puede ser que una cuestión de un golpe de opción en tiempo de ejecución o la variable de entorno? Tengo el ejemplo no funciona con Sh ninguno de los dos, por lo que puede ser Bash puede tratar de ser compatible con Sh?
  • He probado este de nuevo en bash 4.3.25 y ya no funciona. Mi memoria es difusa en esto y no estoy seguro de lo que yo he hecho para llegar a trabajar.
  • la última cmd en un tubo debe afectar a los vars en bash4>=4.2 con shopt -s lastpipetldp.org/LDP/abs/html/bashver4.html#LASTPIPEOPT
InformationsquelleAutor ldog | 2010-04-30

15 Comentarios

  1. 159

    Uso

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

    Que puede truco read en la aceptación de una tubería como este:

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

    o incluso escribir una función como esta:

    read_from_pipe() { read "[email protected]" <&0; }

    Pero no hay ningún punto de sus asignaciones de variables no puede durar! Una tubería puede generar una subshell, donde el ambiente es heredado por valor y no por referencia. Esta es la razón por la read no se molesta con la entrada de tubería – es indefinido.

    FYI, http://www.etalabs.net/sh_tricks.html es una interesante recopilación de la información antigua necesario para luchar contra las rarezas y las incompatibilidades de los shells bourne, sh.

    • Usted puede hacer la asignación último haciendo de este lugar: `test=`echo «hola mundo» | { prueba de lectura; echo $prueba; }«
    • Vamos a intentarlo de nuevo (al parecer escapar comillas simples inclinadas en este marcado es divertido): test=`echo "hello world" | { read test; echo $test; }`
    • ¿puedo preguntar por qué se utiliza {} en lugar de () en la agrupación de los dos comandos?
    • El truco no está en hacer read toma de entrada de la tubería, pero en el uso de la variable en la misma shell que ejecuta el read.
    • el extra { } bloque truco no será necesario en bash4>=4.2 con shopt -s lastpipetldp.org/LDP/abs/html/bashver4.html#LASTPIPEOPT
    • Que funciona a la perfección stackoverflow.com/questions/6980090/…
    • Tengo bash permission denied al intentar utilizar esta solución. Mi caso es muy diferente, pero no pude encontrar una respuesta para ella en cualquier lugar, lo que funcionó para mí era (un ejemplo diferente pero similar a la de uso): pip install -U echo $(ls -t *.py | head -1). En el caso de que alguien tiene un problema similar y se topa con esta respuesta como yo.

  2. 105

    si quieres leer en un montón de datos y el trabajo en cada línea por separado, usted podría usar algo como esto:

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

    si quieres dividir las líneas en varias palabras se pueden utilizar varias variables en lugar de la 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 empiezan a querer hacer algo realmente inteligente con este tipo de cosas es mejor ir por algunas secuencias de comandos de lenguaje como perl, donde se podía intentar algo como esto:

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

    Hay una pronunciada curva de aprendizaje con perl (o supongo que cualquiera de estos idiomas), pero usted encontrará que es mucho más fácil en el largo plazo si usted quiere hacer nada, pero el más sencillo de secuencias de comandos. Me gustaría recomendar el Perl libro de cocina y, por supuesto, El Lenguaje de Programación Perl por Larry Wall et al.

    • «alternativamente» es la forma correcta. No UUoC y no subshell. Consulte BashFAQ/024.
  3. 40

    read no va a leer a partir de un tubo (o, posiblemente, el resultado es perdido debido a que la tubería se crea una subshell). Sin embargo, puede utilizar un aquí de cadena en Bash:

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

    Pero ver a @chepner la respuesta para obtener información acerca de lastpipe.

    • Bonita y sencilla de una línea, fácil de entender. Esta respuesta de las necesidades más upvotes.
  4. 39

    Esta es otra opción

    $ read test < <(echo hello world)
    
    $ echo $test
    hello world
    • La importante ventaja de que <(..) tiene más de $(..) es que <(..) devuelve cada línea de la llamada tan pronto como el comando que se ejecuta hace disponible. $(..), sin embargo, espera a que el comando para completar y generar todos los de su salida antes de cualquier salida disponible para la persona que llama.
  5. 30

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

    stdin=$(cat)
    
    echo "$stdin"

    One-liner prueba de que funciona para mí:

    $ fortune | eval 'stdin=$(cat); echo "$stdin"'
    • Eso es probablemente debido a que «leer» es un comando de bash, y el gato es un binario independiente que será lanzado en un subproceso, por lo que es menos eficiente.
    • a veces la simplicidad y la claridad de triunfo eficiencia 🙂
    • sin duda la más sencilla respuesta
    • El problema me encontré con esto es que si una tubería que no se usa, la secuencia de comandos se bloquea.
    • También, por supuesto. Cualquier programa que intenta leer de la entrada estándar se «cuelgue» si nada se alimenta de ella.
    • pero no es necesariamente el comportamiento esperado de una determinada secuencia de comandos. Si sólo hubiera una manera de controlar la ausencia de stdin con gracia y caer de nuevo a los «normales» de comportamiento si no está presente. Este post tiene casi la misma – se acepta argumentos o la entrada estándar. La única cosa que falta es ser capaz de proporcionar un uso auxiliar si no están presentes.
    • Gracias, esta respuesta en mi opinión es el mejor. Solucionado mi problema.
    • Solución sencilla y elegante.

  6. 25

    bash 4.2 presenta la lastpipe opción, que permite que el código funcione como está escrito, al ejecutar el último comando en una tubería en el shell actual, en lugar de una subshell.

    shopt -s lastpipe
    echo "hello world" | read test; echo test=$test
    • ah! así que bueno, este. si las pruebas en un shell interactivo, también: «set +m» (no se requiere en una .sh script)
  7. 13

    La sintaxis de una forma implícita de la tubería desde un shell de comandos en bash variable es

    var=$(command)

    o

    var=`command`

    En tus ejemplos, que son las tuberías de datos a una sentencia de asignación, que no espera ninguna entrada.

    • La primera forma, var=$(comando), es preferible.
    • ¿Por qué razón?
    • Porque $() se pueden anidar fácilmente. Pensar en JAVA_DIR=$(dirname $(readlink -f $(que java))), y tratar con el». Usted tendrá que escapar tres veces!
    • Genial, gracias por la respuesta
  8. 6

    El primer intento fue muy cerca. Esta variación se debe trabajar:

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

    y el resultado es:

    prueba=hola mundo

    Necesitas apoyos después de que la tubería se encierran en la asignación para la prueba y el eco.

    Sin las llaves, la asignación de la prueba (después de la pipa) es en una concha, y el echo «prueba=$prueba» es separado en una shell que no sabe acerca de esa tarea. Es por eso que usted estaba recibiendo la prueba del «=» en la salida en lugar de «prueba=hola mundo».

  9. 6

    En mis ojos la mejor manera de leer desde la entrada estándar stdin en bash es la siguiente, que también le permite trabajar en las líneas antes de la entrada termina:

    while read LINE; do
        echo $LINE
    done < /dev/stdin
    • Casi me volví loco antes de encontrar este. Muchas gracias por compartir!
  10. 5

    Porque me enamoro de ella, me gustaría dejar una nota.
    He encontrado este hilo, porque tengo que escribir una vieja sh script
    para ser compatible POSIX.
    Esto básicamente significa eludir la tubería/subshell problema introducido por POSIX por la reescritura de código como este:

    some_command | read a b c

    en:

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

    Y un código como este:

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

    en:

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

    Pero éste no se comporta de la misma en la entrada vacía.
    Con la antigua notación el bucle while no se introduce en la entrada vacío,
    pero en POSIX notación es!
    Creo que es debido a la nueva línea antes de EF,
    que no puede ser omitido.
    El POSIX código que se comporta más como el viejo de la notación
    se parece a esto:

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

    En la mayoría de los casos, este debe ser lo suficientemente bueno.
    Pero, por desgracia, todavía no se comporta exactamente igual que la anterior notación
    si some_command imprime una línea en blanco.
    En la antigua notación del cuerpo mientras se ejecuta
    y en notación POSIX, hacemos un descanso en la parte frontal del cuerpo.

    Un enfoque para solucionar este podría tener este aspecto:

    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
  11. 3

    Tuberías algo en una expresión que implique una cesión no se comportan así.

    Lugar, trate de:

    test=$(echo "hello world"); echo test=$test
  12. 3

    Un inteligente guión que puede leer los datos de la TUBERÍA y argumentos de línea de comandos:

    #!/bin/bash
    if [[ -p /proc/self/fd/0 ]]
        then
        PIPE=$(cat -)
        echo "PIPE=$PIPE"
    fi
    echo "[email protected]"

    De salida:

    $ bash test arg1 arg2
    ARGS=arg1 arg2
    
    $ echo pipe_data1 | bash test arg1 arg2
    PIPE=pipe_data1
    ARGS=arg1 arg2

    Explicación: Cuando un script recibe los datos a través de la tubería, y luego la stdin /proc/self/fd/0 va a ser un enlace simbólico a una tubería.

    /proc/self/fd/0 -> pipe:[155938]

    Si no, que se apuntan a la actual terminal:

    /proc/self/fd/0 -> /dev/pts/5

    El bash if -p opción puede comprobar que se trata de un tubo o no.

    cat - lee el de stdin.

    Si utilizamos cat - cuando no hay stdin, se va a esperar para siempre, es por eso que ponemos dentro de la if condición.

    • También puede utilizar /dev/stdin, que es un enlace a /proc/self/fd/0
  13. 2

    El siguiente código:

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

    será trabajar demasiado, pero va a abrir otra nueva sub-shell después de la pipa, donde

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

    no.


    Tuve que deshabilitar el control de trabajo para hacer uso de chepnars‘ método (yo era de ejecutar 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:

    lastpipe

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

    Nota: puesto de control está desactivada de forma predeterminada en un no-shell interactivo y por lo tanto usted no necesita la set +m dentro de un script.

  14. 1

    Creo que estaba tratando de escribir un script de shell que podría tomar de entrada de stdin.
    pero mientras que usted está tratando de hacer en línea, usted se perdió tratando de crear la prueba= variable.
    Creo que no tiene mucho sentido hacerlo en línea, y es por eso que no funciona de la manera que usted espera.

    Yo estaba tratando de reducir

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

    para obtener una línea específica de entrada de varios.
    así que yo podría escribir…

    cat program_file.c | line 34

    así que tengo una pequeña concha programa capaz de leer de la entrada estándar. al igual que usted.

    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 ~ $ 

    hay que ir.

  15. -1

    Cómo sobre esto:

    echo "hello world" | echo test=$(cat)
    • Básicamente un duplicado de mi respuesta.
    • Tal vez, yo diría que el mío es un poco más limpio y más cerca de la código publicado en la pregunta original.

Dejar respuesta

Please enter your comment!
Please enter your name here