Prueba de Bash para cadena vacía con X "" [duplicado]


Esta pregunta ya tiene una respuesta aquí:

Sé que puedo probar una cadena vacía en Bash con -z así:

if [[ -z $myvar ]]; then do_stuff; fi

Pero veo un montón de código escrito como:

if [[ X"" = X"$myvar" ]]; then do_stuff; fi

¿Es ese método más portátil? Es sólo histórico resto de antes de los días de -z? ¿Es para shells POSIX (aunque he visto que se usa en scripts dirigidos a bash)? Listo para mi lección de historia / portabilidad.


Se hizo la misma pregunta sobre la falla del servidor que ¿Cómo determinar si una variable bash está vacía? pero nadie ofreció una explicación en cuanto a por qué ves código con el X"" cosas.

Author: Community, 2011-07-28

2 answers

Fundamentalmente, porque en tiempos pasados, el comportamiento de test era más complejo y no se definía uniformemente en diferentes sistemas (por lo que el código portable tenía que escribirse cuidadosamente para evitar construcciones no portables).

En particular, antes de que test fuera un shell integrado, era un ejecutable separado (y tenga en cuenta que macOS X todavía tiene /bin/test y /bin/[ como ejecutables). Cuando ese fue el caso, escribiendo:

if [ -z $variable ]

Cuando $variable estaba vacío invocaría el programa de prueba a través de su alias [ con 3 argumentos:

argv[0] = "["
argv[1] = "-z"
argv[2] = "]"

Porque la variable estaba vacía por lo que no había nada que expandir. Entonces, la forma segura de escribir el código fue:

if [ -z "$variable" ]

Esto funciona de forma fiable, pasando 4 argumentos al ejecutable test. Por supuesto, el programa de prueba ha sido incorporado a la mayoría de los proyectiles durante décadas, pero el equipo viejo muere duro, y también lo hacen las buenas prácticas aprendidas hace aún más tiempo.

El otro problema resuelto por el prefijo X fue lo que sucedía si las variables incluyen guiones iniciales, o contienen iguales u otros comparadores. Considere (un ejemplo no desparately bueno):

x="-z"
if [ $x -eq 0 ]

¿Es una prueba de cadena vacía con un argumento errado (erróneo), o una prueba de igualdad numérica con un primer argumento no numérico? Diferentes sistemas proporcionaron diferentes respuestas antes de que POSIX estandarizara el comportamiento, alrededor de 1990. Entonces, la forma segura de lidiar con esto fue:

if [ "X$x" = "X0" ]

O (menos generalmente, en mi experiencia, pero completamente equivalente):

if [ X"$x" = X"0" ]

It fue todos los casos de borde como este, atado con la posibilidad de que la prueba era un ejecutable separado, eso significa que el código shell portable todavía utiliza comillas dobles más copiosamente de lo que los shells modernos realmente requieren, y la notación de prefijo X se utilizó para asegurar que las cosas no podían ser malinterpretadas.

 113
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-06 14:19:46

Ah, esta es una de mis preguntas y respuestas preferidas, porque se me ocurrió la respuesta solo pensando en ello. El X se establece en caso de que la cadena comience con un -, que se puede tomar como una bandera para la prueba. Poner un X antes solo elimina ese caso, y la comparación todavía puede mantenerse.

También me gusta esto porque este tipo de truco es casi una herencia del pasado, los tiempos más antiguos de la computación, y lo encuentras cuando intentas leer algunos de los más portátiles scripts de shell (autoconf, configure, etc.))

 10
Author: Diego Sevilla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-28 00:01:34