true script not bash if-statement conditional

script - Bash: uso de `true`



if function bash (4)

Aunque no es estrictamente lo mismo,

if [ x"$SOME_VAR" = x ]; then ... fi

tiende a hacer lo que quieres; ese es el si es verdadero si $SOME_VAR no está definido o (diferencia :) definido como la cadena de longitud cero.

Este código no funciona si SOME_VAR está configurado y -u está establecido. Creo que el siguiente bashismo funciona: "${SOME_VAR-}" = "" .

En muchos guiones que heredé de un ex empleado sigo viendo este patrón:

if (true $SOME_VAR)&>/dev/null; then ... fi

o este

(true $SOME_VAR)&>/dev/null || SOME_VAR="..."

La página de manual de true dice que siempre es verdadera, por lo que sigo preguntándome, ¿cuál es el objetivo de estos controles? En el primer caso, la parte then siempre se ejecuta, en el segundo caso, la parte derecha nunca se ejecuta.


Lo siguiente es probablemente equivalente, y más sencillo:

if [ "${SOME_VAR+x}" ] then ... fi

O, en el caso de asignación:

[ "${SOME_VAR+x}" ] || SOME_VAR="..."

El operador de expansión + expande a una cadena nula si la variable está desarmada, y a x si está asignada (asignada una cadena nula todavía significa asignada). En este caso, puedes reemplazar x por lo que quieras (excepto una cadena nula).

También hay una variante de ${SOME_VAR:+x} . La diferencia es con cadenas nulas :+ expande a una cadena nula si a la variable se le asigna una cadena nula (mientras que + expande a x si se le asigna el valor, incluso si es una cadena nula).


Para complementar Fred :

  • En Bash v4.2 + , el operador menos oscuro y más eficiente -v se puede usar para probar si una variable está definida [1] (tenga en cuenta que no se debe usar $ ):
    [[ -v SOME_VAR ]]

  • En las versiones anteriores de Bash y en las secuencias de comandos que cumplen con POSIX , utilice el enfoque basado en la expansión de parámetros de Fred , que también es más eficiente que el enfoque (true ...) .

  • Si la intención es simplemente proporcionar un valor predeterminado , como en (true $SOME_VAR)&>/dev/null || SOME_VAR="..." (true $SOME_VAR)&>/dev/null || SOME_VAR="..." idioma, use la técnica (compatible con POSIX) sugerida por kojiro , también basada en la expansión de un parámetro :
    SOME_VAR=${SOME_VAR-...} # keep $SOME_VAR value or default to ''...''
    Toby Speight sugiere otra variante compatible con POSIX, ${SOME_VAR=...} , que actualiza directamente la variable con el valor predeterminado, si no está definida; sin embargo, tiene el efecto secundario de expandirse al valor (resultante) que puede o no ser deseado. Una forma concisa, pero también ligeramente oscura de suprimir la expansión, es pasar la expansión a la utilidad de dos puntos (null) (:) , que se expande, pero ignora sus argumentos (en comparación con usar true para el mismo propósito, quizás sea ligeramente menos confuso):
    : ${SOME_VAR=...} # set $SOMEVAR to ''...'' only if not defined

  • Tenga en cuenta que todas las expansiones de parámetros mostradas / mencionadas anteriormente tienen una variante que coloca : antes del operador , que luego actúa no solo cuando la variable no está definida , sino también cuando está definida pero vacía (contiene la cadena nula):
    ${SOME_VAR:+...} , ${SOME_VAR:-...} , ${SOME_VAR:=...}
    Podría decirse que este comportamiento variante es la técnica generalmente más sólida , especialmente dado que cuando el set -u ( set -o nunset ) no está activado, las variables indefinidas se expanden a la cadena nula (vacía).

Para agregar a la explicación de jwodder:

  • El uso de (...) alrededor de true $SOME_VAR para crear una subcategoría es crucial para que esta prueba algo oscura para que la existencia variable funcione según lo previsto.

    • Sin una subshell, la secuencia de comandos completa abortaría.

    • La necesidad de una subshell hace que la técnica no solo sea oscura , sino también ineficaz (aunque eso no se notará realmente con el uso ocasional).

      • Además, si el set -u ( set -o nounset ) pasa a no tener efecto, la técnica trata todas las variables como están definidas.
    • Con la subshell, solo se cancela la subshell, que se refleja en su código de salida para la shell actual: 1 , si la subshell abortó (la variable no existe), 0 caso contrario.
      Por lo tanto, el comando (true ...) solo evalúa (conceptualmente) verdadero si la variable existe.

    • &>/dev/null suprime el mensaje de error de la subshell que se emite si la variable no existe.

      • Como (true $SOME_VAR)2>/dev/null aparte: true nunca produce salida, por lo que es suficiente usar (true $SOME_VAR)2>/dev/null (suprimir stderr solamente) - este cambio hace que la técnica sea compatible con POSIX (aunque todavía no es aconsejable).
  • No es solo set -u declaraciones set -u ( set -o nounset ) dentro de una secuencia de comandos que set -o nounset abortar en caso de acceso a una variable indefinida - invocar bash explícitamente con la opción de línea de comandos -u tiene el mismo efecto.

[1] Desde Bash v4.3 , también puede probar si una variable de matriz tiene un elemento con el índice especificado; p.ej:
a=( one two ); [[ -va[0] ]]
a=( one two ); [[ -va[0] ]] tiene éxito, porque existe un elemento de matriz con índice 0 ; funciona de manera análoga con matrices asociativas.


Si el set -u (también conocido como set -o nounset ) está en vigor, el true $SOME_VAR fallará cuando $SOME_VAR no esté definido. Por lo tanto, esta es una forma de comprobar si la variable está definida.