2011-08-30 19 views
10

el siguiente script con la opción de depuración 'set -e -v' falla en el operador de incremento solo cuando la variable tiene un valor anterior de cero.bash set -e i = 0; let i ++ no acepta

#!/bin/bash 
set -e -v 
i=1; let i++; echo "I am still here" 
i=0; let i++; echo "I am still here" 

i=0; ((i++)); echo "I am still here" 

bash (GNU bash, versión 4.0.33 (1) -RELEASE (x86_64-apple-darwin10), sino también golpe GNU, versión 4.2.4 (1) -RELEASE (x86_64-unknown-linux-gnu))

¿Alguna idea?

+1

Nunca hubiera imaginado que un incremento de aspecto inofensivo hubiera tenido esta interacción involuntaria con 'set -e'. Afortunado, encontré esta pregunta. –

Respuesta

15

la respuesta a mi pregunta es no utilizar vamos (o turno, o ...) sino utilizar

i=$((i+1)) 

cuando se trata de comprobar una escritura del golpe al configurar un 'salida de código de estado distinto de cero 'con

set -e 

el golpe manual indica que set -e tiene el efecto de' Salga inmediatamente si sale un comando simple con un estado distinto de cero. '.

Desafortunadamente vamos (y cambio y ...) devuelve el resultado del cálculo ('Si el último arg evalúa a 0, dejar que devuelve 1; de lo contrario se devuelve 0'). Entonces, en lugar de un código de estado, uno obtiene un valor de retorno de algún tipo. Y a veces este valor de retorno será cero y, a veces, uno dependiendo del cálculo. Por lo tanto, set -e hará que la secuencia de comandos salga dependiendo del resultado de su cálculo. y no hay nada que hacer al respecto ya sea a menos que no lo utiliza nunca o recurrir a

let i++ || true 

como se ha señalado por arnaud576875 que añade cierto carga de CPU adicional.

Usando

let ++i 

funciona sólo para el caso específico que i es no -1, como con let i ++ que sólo funciona para cuando i no es 0. Por lo tanto medias soluciones.

Aunque me encanta Unix, no lo haría de otra manera.

+0

+1 Esta respuesta es la correcta. Hice un script de prueba para verificar las otras opciones de incremento que encontré en Internet y SO (alrededor de 10). Un script en línea se encuentra aquí: http://goo.gl/XYzrK2 – r3x

9

Si el último argumento de let evalúa a 0, dejar que vuelve 1 (así, un no-cero de estado):

Del manual:

let arg [arg ...] 

Cada arg es una expresión aritmética ser evaluado. Si la última arg se evalúa como 0, déjela devuelve 1; 0 se devuelve de lo contrario.

i++ evalúa a cero cuando i es 0 (porque es un post-incremento, por lo que se devuelve el valor anterior de i), SO let rendimientos 1, y debido a set -e, existe bash.

Estas son algunas soluciones:

let ++i   # pre-increment, if you expect `i` to never be -1 
let i++ 1  # add an expression evaluating to non-zero 
let i++ || true # call true if let returns non-zero 
+0

gracias, esto es tan ad hoc hombre. – bliako

0

Mirando el BASH manpage en el set -e:

Salir inmediatamente si una orden simple (ver SHELL gramática anterior) sale con un estado distinto de cero. [...]

Por lo tanto, si alguna instrucción devuelve un código de salida distinto de cero, el shell se cerrará.

Echando un vistazo a la BASH manpage, en el comando let:

Si el último arg evalúa a 0, dejar que devuelve 1; 0 se devuelve de lo contrario.

¡Pero espera! ¡La respuesta a i++ es una y no un cero! Debería haber funcionado!

Una vez más, la respuesta es con la página de manual BASH en el operador de incremento:

Identificación ++ id--: variable de post-incremento y de decremento posterior

bien, no está tan claro. Probar este script de shell:

#!/bin/bash 
set -e -v 
i=1; let ++i; echo "I am still here" 
i=0; let ++i; echo "I am still here" 

i=0; ((++i)); echo "I am still here" 

Hmmm ... eso funciona como se esperaba, y lo único que hice fue el cambio i++-++i en cada línea.

El i++ es un operador de incremento posterior. Eso significa que incrementa idespués de la declaración let devuelve un valor. Dado que i era cero antes de que se incrementara, la instrucción let devuelve un valor distinto de cero.

Sin embargo, ++i es un operador de preincremento . Eso significa que incrementa i antes de devolver el estado de salida. Como i se incrementa a 1, el estado de salida se convierte en cero.

Espero que esto tenga sentido.

+0

lo que no tiene sentido es que let, set -e y los humanos razonables no estén destinados a vivir juntos, ya que nadie escribirá 'let i ++ || verdadero 'a menos que sea una firma de correo electrónico. – bliako

+0

Es el hecho de que 'i ++' no es un operador de incremento, sino un *** operador de incremento *** que arroja personas. La mayoría de las personas no lo saben a menos que sean programadores en C y hayan visto esto: 'foo = bar + i ++;' o 'oldfoo = foo ++' suficientes veces para darles un tumor cerebral. –

+0

No, no es eso, es el hecho de que un código de estado, que 'set -e' usa para verificar el estado, si la operación se completó exitosamente o no, se usa para transmitir información sobre el resultado del cálculo. Los desarrolladores pensaron que era una característica y no un error presentar, a la: let i ++ || echo 'look no hands', pero el resultado final es que necesitamos reescribir el código para depurar, de hecho ya no confío en esto porque hay muchas más operaciones siguiendo esto. Y, por cierto, como una cuestión de consistencia, ¿el bash de ((i = 0; i <10; i ++)) tiene el mismo efecto BOFH? hombre astuto, astuto. – bliako

Cuestiones relacionadas