¿Cómo determinar si una variable bash está vacía?

Respuestas:

1053

Esto devolverá verdadero si una variable se desarma o establece en la cadena vacía ("").

if [ -z "$VAR" ];
duffbeer703
fuente
14
¿Eso incluye si una variable SE ESTABLECE en un valor de ""?
Brent
11
Sí, lo hace ... "-z" prueba una cadena de longitud cero.
David Z
9191
if [ ! -z "$VAR" ];
Aaron Copley
263
lo contrario de -zes-n if [ -n "$VAR" ];
Felipe Alvarez
19
Las comillas dobles aseguran que la variable no se divida. Un simple $varen una línea de comando se dividirá por su espacio en blanco en una lista de parámetros, mientras "$var"que siempre será un solo parámetro. Citar variables a menudo es una buena práctica y le impide tropezar con nombres de archivos que contienen espacios en blanco (entre otras cosas). Ejemplo: después de hacerlo a="x --help", intente cat $a, le dará la página de ayuda cat. Luego intente cat "$a", lo dirá (generalmente) cat: x --help: No such file or directory. En resumen, cite temprano y cite a menudo y casi nunca se arrepentirá.
Score_Under
247

En Bash, cuando no le preocupa la portabilidad a los shells que no lo admiten, siempre debe usar la sintaxis de doble paréntesis:

Cualquiera de los siguientes:

if [[ -z $variable ]]
if [[ -z "$variable" ]]
if [[ ! $variable ]]
if [[ ! "$variable" ]]

En Bash, usando corchetes dobles, las comillas no son necesarias. Se puede simplificar la prueba para una variable que hace contener un valor de:

if [[ $variable ]]

Esta sintaxis es compatible con ksh (al menos ksh93, de todos modos). No funciona en POSIX puro o shells Bourne anteriores como sh o dash.

Vea mi respuesta aquí y BashFAQ / 031 para obtener más información sobre las diferencias entre corchetes dobles y simples.

Puede probar para ver si una variable está específicamente desarmada (a diferencia de una cadena vacía):

if [[ -z ${variable+x} ]]

donde la "x" es arbitraria.

Si desea saber si una variable es nula pero no está desarmada:

if [[ -z $variable && ${variable+x} ]]
Dennis Williamson
fuente
1
Eso if [[ $variable ]]funcionó bien para mí y ni siquiera necesitaba lo set -uque requería una de las otras soluciones propuestas.
Teemu Leisti
3
Creo que esto es mejor que la respuesta aceptada.
qed
2
¿Por qué recomienda una característica no portátil cuando hacerlo no ofrece ningún beneficio?
Alastair Irvine
19
@AlastairIrvine: Menciono la portabilidad en la primera oración de mi respuesta, el título y el cuerpo de la pregunta contienen la palabra "Bash" y la pregunta está etiquetada como bash , y la estructura de doble parche ofrece claras ventajas de muchas maneras. Y no recomiendo mezclar estilos de corchetes por razones de consistencia y facilidad de mantenimiento. Si necesita la máxima portabilidad del mínimo común denominador, use en shlugar de Bash. Si necesita las capacidades mejoradas que proporciona, use Bash y úselo completamente.
Dennis Williamson
2
@BrunoBronosky: Revertí la edición. No hay requisitos para ;al final. El thenpuede estar en la siguiente línea sin punto y coma.
Dennis Williamson el
230

Una variable en bash (y cualquier shell compatible con POSIX) puede estar en uno de tres estados:

  • desarmado
  • establecer en la cadena vacía
  • establecido en una cadena no vacía

La mayoría de las veces solo necesita saber si una variable está establecida en una cadena no vacía, pero ocasionalmente es importante distinguir entre unset y set en la cadena vacía.

Los siguientes son ejemplos de cómo puede probar las diversas posibilidades, y funciona en bash o en cualquier shell compatible con POSIX:

if [ -z "${VAR}" ]; then
    echo "VAR is unset or set to the empty string"
fi
if [ -z "${VAR+set}" ]; then
    echo "VAR is unset"
fi
if [ -z "${VAR-unset}" ]; then
    echo "VAR is set to the empty string"
fi
if [ -n "${VAR}" ]; then
    echo "VAR is set to a non-empty string"
fi
if [ -n "${VAR+set}" ]; then
    echo "VAR is set, possibly to the empty string"
fi
if [ -n "${VAR-unset}" ]; then
    echo "VAR is either unset or set to a non-empty string"
fi

Aquí está lo mismo pero en forma de tabla práctica:

                        +-------+-------+-----------+
                VAR is: | unset | empty | non-empty |
+-----------------------+-------+-------+-----------+
| [ -z "${VAR}" ]       | true  | true  | false     |
| [ -z "${VAR+set}" ]   | true  | false | false     |
| [ -z "${VAR-unset}" ] | false | true  | false     |
| [ -n "${VAR}" ]       | false | false | true      |
| [ -n "${VAR+set}" ]   | false | true  | true      |
| [ -n "${VAR-unset}" ] | true  | false | true      |
+-----------------------+-------+-------+-----------+

La ${VAR+foo}construcción se expande a la cadena vacía si no VARestá establecida o foosi VARse establece en cualquier cosa (incluida la cadena vacía).

La ${VAR-foo}construcción se expande al valor de VARif set (incluido el set a la cadena vacía) y fooif unset. Esto es útil para proporcionar valores predeterminados reemplazables por el usuario (por ejemplo, ${COLOR-red}dice usar a redmenos que la variable COLORse haya establecido en algo).

La razón por la [ x"${VAR}" = x ]que a menudo se recomienda para probar si una variable está desarmada o configurada en la cadena vacía es porque algunas implementaciones del [comando (también conocido como test) tienen errores. Si VARse establece en algo así -n, entonces algunas implementaciones harán lo incorrecto cuando se den [ "${VAR}" = "" ]porque el primer argumento [se interpreta erróneamente como el -noperador, no como una cadena.

Richard Hansen
fuente
3
La prueba de una variable establecida en la cadena vacía también se puede hacer usando [ -z "${VAR-set}" ].
nwellnhof
@nwellnhof: ¡Gracias! Actualicé mi respuesta para usar la sintaxis más breve.
Richard Hansen
¿Cuál es la diferencia entre la primera y la última construcción? Ambos corresponden a "VAR está desarmado o configurado en una cadena no vacía".
Faheem Mitha
1
@ FaheemMitha: No es tu culpa, mi respuesta fue difícil de leer. Agregué una tabla para que la respuesta sea más clara.
Richard Hansen
2
Los cheques sin configurar no son confiables. Si el usuario llamó set -uo set -o nounseten bash, entonces la prueba solo dará como resultado el error "bash: VAR: variable independiente". Visite stackoverflow.com/a/13864829 para obtener una verificación sin configurar más confiable. Mi opción para verificar si una variable es nula o no está establecida [ -z "${VAR:-}" ]. Mi verificación de si una variable no está vacía es [ "${VAR:-}" ].
Kevin Jin
38

-z Es la mejor manera.

Otra opción que he usado es establecer una variable, pero puede ser anulada por otra variable, por ejemplo

export PORT=${MY_PORT:-5432}

Si la $MY_PORTvariable está vacía, PORTse establece en 5432; de lo contrario, PORT se establece en el valor de MY_PORT. Tenga en cuenta que la sintaxis incluye los dos puntos y el guión.

Rory
fuente
Accidentalmente encontré esto hoy, y era exactamente lo que quería. ¡Gracias! Tengo que tolerar set -o nounseten algunos guiones.
opello
24

Si está interesado en distinguir los casos de estado de conjunto vacío frente a estado no establecido, mire la opción -u para bash:

$ set -u
$ echo $BAR
bash: BAR: unbound variable
$ [ -z "$BAR" ] && echo true
bash: BAR: unbound variable
$ BAR=""
$ echo $BAR

$ [ -z "$BAR" ] && echo true
true
MikeyB
fuente
8

Una alternativa que he visto [ -z "$foo" ]es la siguiente, sin embargo, no estoy seguro de por qué las personas usan este método, ¿alguien sabe?

[ "x${foo}" = "x" ]

De todos modos, si no permite variables no establecidas (ya sea por set -uo set -o nounset), entonces tendrá problemas con ambos métodos. Hay una solución simple para esto:

[ -z "${foo:-}" ]

Nota: esto dejará su variable undef.

errant.info
fuente
3
Hay un comentario sobre la alternativa -zen pubs.opengroup.org/onlinepubs/009695399/utilities/test.html . Básicamente, no está destinado a ser una alternativa a -z. Más bien, se ocupa de los casos en que $foopodría expandir a algo que comienza con un meta que [o testse confunde con. Poner un no metacarácter arbitrario al principio elimina esa posibilidad.
James Sneeringer el
6

La pregunta pregunta cómo verificar si una variable es una cadena vacía y las mejores respuestas ya están dadas para eso.
Pero llegué aquí después de un período de programación en php y lo que realmente estaba buscando era una verificación como la función vacía en php trabajando en un shell bash.
Después de leer las respuestas, me di cuenta de que no estaba pensando correctamente en bash, pero de todos modos en ese momento una función como vacío en php hubiera sido muy útil en mi código bash.
Como creo que esto puede sucederle a otros, decidí convertir la función vacía de php en bash

De acuerdo con el manual de php :
una variable se considera vacía si no existe o si su valor es uno de los siguientes:

  • "" (una cadena vacía)
  • 0 (0 como un entero)
  • 0.0 (0 como flotante)
  • "0" (0 como una cadena)
  • una matriz vacía
  • una variable declarada, pero sin un valor

Por supuesto, los casos nulo y falso no se pueden convertir en bash, por lo que se omiten.

function empty
{
    local var="$1"

    # Return true if:
    # 1.    var is a null string ("" as empty string)
    # 2.    a non set variable is passed
    # 3.    a declared variable or array but without a value is passed
    # 4.    an empty array is passed
    if test -z "$var"
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is zero (0 as an integer or "0" as a string)
    elif [ "$var" == 0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is 0.0 (0 as a float)
    elif [ "$var" == 0.0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return
    fi

    [[ $( echo "" ) ]]
}



Ejemplo de uso:

if empty "${var}"
    then
        echo "empty"
    else
        echo "not empty"
fi



Demostración:
el siguiente fragmento:

#!/bin/bash

vars=(
    ""
    0
    0.0
    "0"
    1
    "string"
    " "
)

for (( i=0; i<${#vars[@]}; i++ ))
do
    var="${vars[$i]}"

    if empty "${var}"
        then
            what="empty"
        else
            what="not empty"
    fi
    echo "VAR \"$var\" is $what"
done

exit

salidas:

VAR "" is empty
VAR "0" is empty
VAR "0.0" is empty
VAR "0" is empty
VAR "1" is not empty
VAR "string" is not empty
VAR " " is not empty

Dicho esto, en una lógica bash, las comprobaciones de cero en esta función pueden causar problemas secundarios en mi humilde opinión, cualquiera que use esta función debería evaluar este riesgo y tal vez decidir cortar esas comprobaciones dejando solo el primero.

Luca Borrione
fuente
Dentro de la función empty: ¿por qué escribiste en [[ $( echo "1" ) ]] ; returnlugar de simplemente return 1?
Dor
5

todo el if-then y -z son innecesarios.

["$ foo"] && echo "foo no está vacío"
["$ foo"] || echo "foo está realmente vacío"

fuente
3
Eso fallará si foo contiene solo espacios
Brian
2
También fallará en algunos shells si foo comienza con un guión, ya que se interpreta como una opción. Por ejemplo, en solaris ksh , zsh y bash no son un problema, sh y / bin / test fallarán
ktf
4

Esto es cierto exactamente cuando $ FOO está configurado y vacío:

[ "${FOO+x}" = x ] && [ -z "$FOO" ]

fuente
4

Personalmente prefiero una forma más clara de verificar:

if [ "${VARIABLE}" == "" ]; then
  echo VARIABLE is empty
else
  echo VARIABLE is not empty
fi
Fedir RYKHTIK
fuente
1
Algunas conchas no aceptan el doble signo igual.
Dennis Williamson
1
La pregunta era sobre bash. Estoy usando bash Funciona bien para mi ¿De qué estás hablando exactamente?
Fedir RYKHTIK
2
Si usa Bash, debe usar corchetes dobles. Mi comentario anterior fue una simple declaración de hechos para aquellos que podrían leer su respuesta y estar usando un shell diferente.
Dennis Williamson
los corchetes simples están bien en este caso, consulte serverfault.com/questions/52034/…
Luca Borrione
4

extensión oneliner de la solución de duffbeer703 :

#! /bin/bash
[ -z "$1" ] || some_command_that_needs_$1_parameter
andrej
fuente
4

Mis 5 centavos: también hay una sintaxis más corta que if ...esta:

VALUE="${1?"Usage: $0 value"}"

Esta línea establecerá VALOR si se ha proporcionado un argumento e imprimirá un mensaje de error antepuesto con el número de línea del script en caso de error (y terminará la ejecución del script).

Se puede encontrar otro ejemplo en la guía de abdominales (busque el «Ejemplo 10-7»).

gluk47
fuente
0

No es una respuesta exacta, pero me encontré con este truco. Si la cadena que busca proviene de "un comando", puede almacenar el comando en un entorno. variable y luego ejecutarlo cada vez para la instrucción if, ¡entonces no se necesitan corchetes!

Por ejemplo, este comando, que determina si estás en Debian:

grep debian /proc/version

ejemplo completo:

IS_DEBIAN="grep -i debian /proc/version"

if $IS_DEBIAN; then
  echo 'yes debian'
else
  echo 'non debian'
fi

Entonces, esto es como una forma indirecta (volver a ejecutarlo cada vez) para verificar una cadena vacía (está comprobando la respuesta de error del comando, pero también está devolviendo una cadena vacía).

rogerdpack
fuente