Pregunta

Veo esto a menudo en los scripts de compilación de proyectos que usan autotools (autoconf, automake). Cuando alguien quiere verificar el valor de una variable de shell, con frecuencia usa este lenguaje:

if test "x$SHELL_VAR" = "xyes"; then
...

¿Cuál es la ventaja de esto al simplemente verificar el valor de esta manera?

if test $SHELL_VAR = "yes"; then
...

Pienso que debe haber alguna razón por la que veo esto tan a menudo, pero no puedo entender qué es.

¿Fue útil?

Solución

Si está utilizando un shell que hace la sustitución simple y la variable SHELL_VAR no existe (o está en blanco), entonces debe tener cuidado con el borde casos. Las siguientes traducciones sucederán:

if test $SHELL_VAR = yes; then        -->  if test = yes; then
if test x$SHELL_VAR = xyes; then      -->  if test x = xyes; then

El primero de estos generará un error ya que el primer argumento para test ha desaparecido. El segundo no tiene ese problema.

Su caso se traduce de la siguiente manera:

if test "x$SHELL_VAR" = "xyes"; then  -->  if test "x" = "xyes"; then

Puede parecer un poco redundante, ya que tiene tanto las comillas como la " x " pero también manejará una variable con espacios en ella, sin dar como dos argumentos al comando test .

La otra razón (aparte de las variables vacías) tiene que ver con el procesamiento de opciones. Si escribes:

if test "$1" = "abc" ; then ...

y $ 1 tiene el valor -n o -z o cualquier otra opción válida para el comando test , la sintaxis es ambigua. El x en la parte frontal evita que se detecte un guión inicial como una opción para probar .

Ten en cuenta que esto depende del shell. Algunos shells ( csh para uno, creo) se quejarán amargamente si la variable de entorno no existe en lugar de simplemente devolver una cadena vacía).

Otros consejos

La otra razón por la que nadie más ha mencionado aún está relacionada con el procesamiento de opciones. Si escribes:

if [ "$1" = "abc" ]; then ...

y $ 1 tiene el valor '-n', la sintaxis del comando de prueba es ambigua; No está claro lo que estabas probando. La 'x' en la parte frontal evita que un guión inicial cause problemas.

Tienes que estar buscando shells realmente antiguos para encontrar uno donde el comando de prueba no tenga soporte para -n o -z ; el comando test de la Versión 7 (1978) los incluyó. No es del todo irrelevante: algunas cosas de la Versión 6 de UNIX se escaparon a BSD, pero en estos días, sería muy difícil encontrar algo tan antiguo en el uso actual.

No usar comillas dobles alrededor de los valores es peligroso, como señalaron otras personas. De hecho, si existe la posibilidad de que los nombres de los archivos contengan espacios (MacOS X y Windows lo alientan hasta cierto punto, y Unix siempre lo ha admitido, aunque herramientas como xargs lo dificultan), entonces debería incluya los nombres de los archivos entre comillas dobles cada vez que los use también. A menos que esté a cargo del valor (p. Ej., Durante el manejo de opciones, y establezca la variable en 'no' al inicio y 'sí' cuando se incluya un indicador en la línea de comando), no es seguro usar formas de variables sin comillas. hasta que haya demostrado su seguridad, y puede hacerlo todo el tiempo para muchos propósitos. O documente que sus scripts fallarán horriblemente si los usuarios intentan procesar archivos con espacios en blanco en los nombres. (Y también hay otros personajes de los que preocuparse: las comillas invertidas pueden ser bastante desagradables, por ejemplo).

Hay dos razones que conozco para esta convención:

http://tldp.org/LDP/abs/html/comparison- ops.html

  

En una prueba compuesta, incluso citar la variable de cadena podría no ser suficiente.   [-n " $ cadena " -o " $ a " = " $ b " ] puede causar un error con algunas versiones de   Bash si $ string está vacío. La forma segura es añadir un carácter extra a   posiblemente variables vacías, [" x $ cadena " ! = x -o " x $ a " = " x $ b " ] (las " x's " cancelan).

Segundo, en otros shells que Bash, especialmente los más antiguos, las condiciones de prueba como '-z' para probar una variable vacía no existían, así que mientras esto:

if [ -z "$SOME_VAR" ]; then
  echo "this variable is not defined"
fi

funcionará bien en BASH, si apunta a la portabilidad en varios entornos UNIX en los que no puede estar seguro de que el shell predeterminado sea Bash y de que sea compatible con la condición de prueba -z, es más seguro usar el formulario si [" x $ SOME_VAR " = " x " ] ya que siempre tendrá el efecto deseado. Esencialmente, este es un viejo truco de shell scripting para encontrar una variable vacía, y todavía se usa hoy en día para la compatibilidad con versiones anteriores a pesar de que hay métodos más limpios disponibles.

Recomiendo en su lugar:

if test "yes" = "$SHELL_VAR"; then

ya que elimina el feo x , y aún resuelve el problema mencionado por https: // stackoverflow.com/a/174288/895245 que $ SHELL_VAR puede comenzar con - y puede leerse como una opción.

Creo que se debe a

SHELLVAR=$(true)
if test $SHELLVAR  = "yes" ; then echo "yep" ; fi 

# bash: test: =: unary operator expected

así como

if test $UNDEFINEDED = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected

y

SHELLVAR=" hello" 
if test $SHELLVAR = "hello" ; then echo "yep" ; fi
# yep 

sin embargo, esto normalmente debería funcionar

SHELLVAR=" hello"
if test "$SHELLVAR" = "hello" ; then echo "yep" ; fi 
#<no output>

pero cuando se queja en la salida en otro lugar, es difícil decir de qué se quejan, supongo, así que

SHELLVAR=" hello"
if test "x$SHELLVAR" = "xhello" ; then echo "yep" ; fi 

funciona igual de bien, pero sería más fácil de depurar.

Si no haces el " x $ SHELL_VAR " cosa, entonces si $ SHELL_VAR no está definido, aparece un error sobre " = " no ser un operador monádico o algo así.

Solía ??hacer eso en DOS cuando SHELL_VAR podría no estar definido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top