Estoy confundido acerca de qué código de error el comando devolverá cuando la ejecución de una asignación de variable claramente y con la sustitución de comandos:

a=$(false); echo $?

Se emite 1, que me dejó pensar que la asignación de variable no barrer o producir de nuevo el código de error después de la última. Pero cuando he intentado esto:

false; a=""; echo $?

Se emite 0, obviamente, esto es lo que a="" devuelve y anular 1 devuelto por false.

Quiero saber por qué sucede esto, ¿hay alguna particularidad en la asignación de variable que difiere de otros comandos normales? O simplemente ser causa a=$(false) se considera un solo comando y sólo la sustitución de comandos de la parte de sentido?

— UPDATE —

Gracias a todos, a partir de las respuestas y comentarios que he recibido en el punto «Cuando se asigna una variable mediante la sustitución de comandos, el estado de salida es el estado de la orden.» (por @Barmar), esta explicación es perfectamente claro y fácil de entender, pero hablar no es lo suficientemente precisa como para los programadores, quiero ver la referencia de este punto de autoridades tales como TLDP o GNU hombre de la página, por favor, ayúdame a encontrar, gracias de nuevo!

  • TLDP no es una fuente de autoridad — el ABS es francamente infame para la presentación de las malas prácticas en bash, tanto como w3schools es en el JavaScript mundo.
InformationsquelleAutor Reorx | 2013-11-23

4 Comentarios

  1. 58

    Al ejecutar un comando como $(command) permite la salida de la orden para reemplazar el propio.

    Cuando dices:

    a=$(false)             # false fails; the output of false is stored in the variable a

    la salida producida por el comando false se almacena en la variable a. Por otra parte, el código de salida es el mismo que el producido por el comando. help false diría:

    false: false
        Return an unsuccessful result.
    
        Exit Status:
        Always fails.

    Por otro lado, diciendo:

    $ false                # Exit code: 1
    $ a=""                 # Exit code: 0
    $ echo $?              # Prints 0

    hace que el código de salida para la asignación a a a ser devueltos que es 0.


    EDICIÓN:

    Citando la manual:

    Si una de las expansiones contenía una sustitución de comandos, la salida
    estado del comando es el estado de salida del último comando
    la sustitución se realiza.

    Citando BASHFAQ/002:

    ¿Cómo puedo almacenar el valor de retorno y/o la salida de un comando en un
    variable?

    output=$(command)

    status=$?

    La asignación a output no tiene ningún efecto sobre command‘s estado de salida, que
    todavía está en $?.

    • Tenga en cuenta que esto no se aplica a local variables (por ejemplo, local output=$(command)), porque local es un comando de sí mismo y de su salida de código de sobrescribirá de la función asignada.
    • esta distinción que hace la diferencia, gracias por decírmelo!
    • Con respecto a @sevko & @qodeninja ‘s comentarios acerca de locals, esto puede ser fácilmente evitados mediante la inicialización después de la declaración, a menos que la variable es también readonly: local my_var; my_var=$(command); local status=$?
    • Mi dios, esto desperdicia mucho de mi tiempo. Gracias @sevko, yo nunca di cuenta de esto por mi cuenta.
  2. 11

    Tenga en cuenta que este no es el caso cuando se utiliza local dentro de una función. Que es sutilmente diferente comportamiento que se describe en el que la aceptó respuesta, y el enlace publicado aquí: http://mywiki.wooledge.org/BashFAQ/002

    Tomar este script en bash por ejemplo:

    #!/bin/bash
    function funWithLocalVar() {
        local output="$(echo "Doing some stuff.";exit 1)"
        local exitCode=$?
        echo "output: $output"
        echo "exitCode: $exitCode"
    }
    
    function funWithoutLocalVar() {
        output="$(echo "Doing some stuff.";exit 1)"
        local exitCode=$?
        echo "output: $output"
        echo "exitCode: $exitCode"
    }
    
    funWithLocalVar
    funWithoutLocalVar

    Aquí está la salida de este:

    nick.[email protected]-laptop1:~$ ./tmp.sh 
    output: Doing some stuff.
    exitCode: 0
    output: Doing some stuff.
    exitCode: 1

    Tal vez a nadie le importa, pero lo hice. Me tomó un minuto para averiguar por qué mi código de estado fue siempre 0 cuando claramente no era a veces. No es 100% claro el por qué. Pero sólo sabiendo esto ayudó.

    • La razón es que local (del mismo modo que para export) es un bash función integrada, y la forma en que se invoca con el primer ejemplo de resultado en un éxito, por lo tanto un 0 código de salida.
  3. 2

    Me encontré con el mismo problema de ayer (Agosto 29 de 2018).

    Además local mencionado en Nick P. la respuesta y @sevko comentario en el aceptado respuesta, declare en el ámbito global también tiene el mismo comportamiento.

    Aquí está mi código Bash:

    #!/bin/bash
    
    func1()
    {
        ls file_not_existed
        local local_ret1=$?
        echo "local_ret1=$local_ret1"
    
        local local_var2=$(ls file_not_existed)
        local local_ret2=$?
        echo "local_ret2=$local_ret2"
    
        local local_var3
        local_var3=$(ls file_not_existed)
        local local_ret3=$?
        echo "local_ret3=$local_ret3"
    }
    
    func1
    
    ls file_not_existed
    global_ret1=$?
    echo "global_ret1=$global_ret1"
    
    declare global_var2=$(ls file_not_existed)
    global_ret2=$?
    echo "global_ret2=$global_ret2"
    
    declare global_var3
    global_var3=$(ls file_not_existed)
    global_ret3=$?
    echo "global_ret3=$global_ret3"

    La salida:

    $ ./declare_local_command_substitution.sh 2>/dev/null 
    local_ret1=2
    local_ret2=0
    local_ret3=2
    global_ret1=2
    global_ret2=0
    global_ret3=2

    Nota: los valores de local_ret2 y global_ret2 en el resultado anterior. Los códigos de salida son sobrescritos por local y declare.

    Mi Bash versión:

    $ echo $BASH_VERSION 
    4.4.19(1)-release
  4. 1

    (no una respuesta a la pregunta original, pero demasiado largo para el comentario)

    Nota que export A=$(false); echo $? salidas 0! Al parecer, el reglamento citado en devnull la respuesta ya no se aplican. Para agregar un poco de contexto a la cita (el énfasis es mío):

    3.7.1 Simple Comando De Expansión

    Si hay un nombre de comando a la izquierda después de la expansión, la ejecución se realiza como se describe a continuación. Lo contrario, el comando de las salidas. Si una de las expansiones contenía una sustitución de comandos, el estado de salida del comando es el estado de salida del último comando de sustitución realizada. Si no hay comando de sustituciones, el comando sale con un estado de cero.

    3.7.2 Comando de Búsqueda y Ejecución [ — este es el «de abajo» caso]

    IIUC el manual describe var=foo como caso especial de var=foo command... sintaxis (bastante confuso!). El «estado de salida del último comando de sustitución» regla sólo se aplica a los no-comando caso.

    Aunque es tentador pensar en export var=foo como «modificado de asignación de sintaxis», no es — export es un builtin comando (que sólo pasa a asumir la tarea como args).

    => Si desea exportar un var Y la captura de la sustitución de comandos de estado, hacerlo en 2 etapas:

    A=$(false)
    # ... check $?
    export A

    De esta manera también trabaja en set -e modo — sale inmediatamente si el comando de sustitución de retorno no 0.

Dejar respuesta

Please enter your comment!
Please enter your name here