¿Por qué 0 es verdadero pero falso es 1 en el caparazón?

false; echo $? 

Lo anterior dará como resultado 1 , que es contradictorio con todos los demás lenguajes de progtwigción que conozco.

¿Alguna razón en esto?

Es una convención, pero particularmente útil cuando lo piensas. En general, si un progtwig tiene éxito, eso es todo lo que necesita saber. Sin embargo, si falla, es posible que necesite conocer todo tipo de información sobre la falla: por qué sucedió, cómo solucionarla, etc. Tener un promedio cero de “éxito” y una falla media distinta de cero le permite verificar con bastante facilidad el éxito. e investigue el error particular para más detalles si lo desea. Muchas API y frameworks tienen una convención similar: las funciones que tienen éxito devuelven 0 y las que fallan devuelven un código de error que describe el caso particular de falla.

Bash es un lenguaje de progtwigción (scripting), pero también es un shell y una interfaz de usuario. Si 0 era un error, entonces el progtwig solo podría presentar un tipo de error.

Sin embargo, en Bash, cualquier valor distinto de cero es un error, y podemos usar cualquier número del 1-255 para representar un error. Esto significa que podemos tener muchos tipos diferentes de errores. 1 es un error general, 126 significa que un archivo no se puede ejecutar, 127 significa ‘comando no encontrado’, etc. Aquí hay una lista de códigos de salida reservados de Bash que muestra algunos de los códigos de salida más comunes.

También hay muchos tipos de éxito (el estado de salida es 0 ). Sin embargo, un éxito le permitirá avanzar al siguiente paso: puede imprimir resultados en una pantalla, ejecutar un comando, etc.

Hay dos problemas relacionados aquí.

Primero, la pregunta del OP, ¿Por qué 0 es verdadero pero falso es 1 en el caparazón? y el segundo, ¿por qué las aplicaciones devuelven 0 para el éxito y no cero para la falla?

Para responder a la pregunta del OP, necesitamos entender la segunda pregunta. Las numerosas respuestas a esta publicación han descrito que se trata de una convención y se han enumerado algunas de las sutilezas que brinda esta convención. Algunas de estas sutilezas se resumen a continuación.

¿Por qué las aplicaciones devuelven 0 para el éxito y no cero para la falla?

El código que invoca una operación necesita saber dos cosas sobre el estado de salida de la operación. ¿Salió la operación con éxito? [* 1] Y si la operación no sale exitosamente, ¿por qué la operación salió sin éxito? Cualquier valor podría usarse para denotar el éxito. Pero 0 es más conveniente que cualquier otro número porque es portátil entre plataformas. Resumiendo la respuesta de xibo a esta pregunta el 16 de agosto de 2011:

Zero es independiente de la encoding.

Si quisiéramos almacenar uno (1) en una palabra entera de 32 bits, la primera pregunta sería “palabra big-endian o palabra little-endian?”, Seguida de “¿por cuánto tiempo los bytes componen una palabra little-endian? “, mientras que cero siempre tendrá el mismo aspecto.

También se debe esperar que algunas personas emitan errno a char o corto en algún punto, o incluso flotar. (int) ((char) ENOLCK) no es ENOLCK cuando char no tiene al menos 8 bits de longitud (las máquinas de caracteres ASCII de 7 bits son compatibles con UNIX), mientras que (int) ((char) 0) es 0 independiente de la detalles arquitectónicos de char.

Una vez que se determina que 0 será el valor de retorno para el éxito, entonces tiene sentido utilizar cualquier valor distinto de cero para el fracaso. Esto permite que muchos códigos de salida respondan a la pregunta de por qué falló la operación.

¿Por qué 0 es verdadero pero falso es 1 en el caparazón?

Uno de los usos fundamentales de shells es automatizar los procesos mediante scripts. Por lo general, esto significa invocar una operación y luego hacer otra cosa de forma condicional en función del estado de salida de la operación. Philippe A. explicó muy bien en su respuesta a esta publicación que

En bash y en shells unix en general, los valores de retorno no son booleanos. Son códigos de salida enteros.

Entonces es necesario interpretar el estado de salida de estas operaciones como un valor booleano. Tiene sentido asignar un estado de salida exitoso ( 0 ) a verdadero y cualquier estado de salida distinto de cero / falla a falso. Hacer esto permite la ejecución condicional de comandos de shell encadenados.

Aquí hay un ejemplo mkdir deleteme && cd $_ && pwd . Como el shell interpreta 0 como verdadero, este comando funciona cómodamente. Si el intérprete de comandos interpretara 0 como falso, entonces tendría que invertir el estado de salida interpretado para cada operación.

En resumen, no tendría sentido que el intérprete de comandos interprete 0 como falso, dado el convenio de que las aplicaciones devuelven 0 para un estado de salida exitoso.


[* 1]: Sí, muchas veces las operaciones deben devolver algo más que un simple mensaje de éxito, pero eso está más allá del scope de este hilo.

Ver también el Apéndice E en la Guía Avanzada de Bash-Scripting

Es solo una convención que un código de salida 0 significa éxito. EXIT_SUCCESS será 0 en casi todos los sistemas modernos.

EDITAR:

“¿Por qué tanto la prueba 0 como la prueba 1 devuelven 0 (éxito)?”

Esa es una pregunta completamente diferente. La respuesta es que pasar un único argumento para probar siempre da como resultado el éxito a menos que ese argumento sea la cadena nula (“”). Ver la documentación de Open Group .

El único punto fundamental que encuentro importante de entender es esto. En bash y en shells unix en general, los valores de retorno no son booleanos. Son códigos de salida enteros. Como tal, debe evaluarlos de acuerdo con la convención diciendo que 0 significa éxito, y otros valores significan algún error.

Con test operadores de test , [ ] o [[ ]] , las condiciones de bash se evalúan como verdaderas en caso de un código de salida de 0 (el resultado de / bin / true). De lo contrario, se evalúan como falso.

Las cadenas se evalúan de forma diferente que los códigos de salida:

 if [ 0 ] ; then echo not null ; fi if [ $(echo 0) ] ; then echo not null ; fi if [ -z "" ] ; then echo null ; fi 

El operador aritmético (( )) interpreta 1 y 0 como verdadero y falso. Pero ese operador no puede usarse como un reemplazo completo para la test , [ ] o [[ ]] . Aquí hay un ejemplo que muestra cuando el operador aritmético es útil:

 for (( counter = 0 ; counter < 10 ; counter ++ )) ; do if (( counter % 2 )) ; then echo "odd number $counter" ; fi done 

Normalmente, los progtwigs devuelven cero para el éxito, no cero para la falla; false devuelve 1 porque es un valor conveniente distinto de cero, pero en general cualquier valor distinto de cero significa falla de algún tipo, y muchos progtwigs devolverán diferentes valores distintos de cero para indicar modos de falla diferentes

AFAIK esto viene de la convención de C de que deberías devolver 0 si lo lograste. Ver:

 man close 

La mayor parte de la API C (POSIX) se construye así. http://en.wikipedia.org/wiki/C_POSIX_library

Intenta equiparar verdadero / falso con éxito / fracaso.

¡Son dos dicotomías completamente, aunque sutilmente al principio, diferentes!

En las secuencias de comandos shell, no existe tal cosa como verdadero / falso. Las ‘expresiones’ del shell no se interpretan como verdadero / falso. Por el contrario, las ‘expresiones’ del shell son procesos que tienen éxito o fallan.

Obviamente, un proceso puede fallar por muchas razones. Por lo tanto, necesitamos códigos de conjunto más grandes para mapear posibles fallas. Los enteros positivos hacen el truco. Por otro lado, si el proceso tiene éxito, eso significa que hizo exactamente lo que se suponía que debía hacer. Como solo hay una forma de hacerlo, solo necesitamos un código. 0 hace el truco.

En C, estamos creando un progtwig. En un script de shell, estamos ejecutando varios progtwigs para hacer algo.

¡Diferencia!

es una convención que se remonta a los primeros días de Unix.

Por convención, todas las llamadas al sistema devuelven 0 si tienen éxito, de lo contrario, no es cero, porque entonces se pueden usar diferentes números para indicar un motivo de falla diferente.

Shells sigue esta convención, 0 significa que el último comando fue exitoso, de lo contrario no es cero. De manera similar, el valor de retorno distinto de cero es útil para los mensajes de error de salida: por ejemplo, 1: “muerte cerebral”, 2: “sin corazón”, etc.