¿Cómo comprobar si una variable está establecida en Bash?


¿Cómo sé si una variable está establecida en Bash?

Por ejemplo, ¿cómo puedo comprobar si el usuario dio el primer parámetro a una función?

function a {
    # if $1 is set ?
}
Author: nbro, 2010-08-30

30 answers

(Generalmente) De la manera correcta

if [ -z ${var+x} ]; then echo "var is unset"; else echo "var is set to '$var'"; fi

Donde ${var+x} es una expansión de parámetro que se evalúa como nada si var no está configurado, y sustituye la cadena x de lo contrario.

Comillas Digresión

Las comillas se pueden omitir (por lo que podemos decir ${var+x} en lugar de "${var+x}") porque esta sintaxis y uso garantiza que esto solo se expandirá a algo que no requiere comillas (ya que se expande a x (que no contiene saltos de palabra por lo que no necesita comillas), o nada (que resulta en [ -z ], que convenientemente evalúa al mismo valor (verdadero) que [ -z "" ] también)).

Sin embargo, mientras que las citas se pueden omitir con seguridad, y no era inmediatamente obvio para todos (ni siquiera era aparente para el primer autor de esta explicación de citas que también es un codificador de Bash importante), a veces sería mejor escribir la solución con comillas como [ -z "${var+x}" ], con el costo muy pequeño posible de una penalización de velocidad O(1). El primer autor también agregó esto como un comentario junto al código que usa esta solución dando la URL a esta respuesta, que ahora también incluye la explicación de por qué las comillas se pueden omitir de forma segura.

(A menudo) El camino equivocado

if [ -z "$var" ]; then echo "var is blank"; else echo "var is set to '$var'"; fi

Esto a menudo es incorrecto porque no distingue entre una variable que no está establecida y una variable que está establecida en la cadena vacía. Es decir, si var='', entonces la solución anterior generará "var está en blanco".

La distinción entre unset y " set to the empty string " es esencial en situaciones en las que el usuario tiene que especificar una extensión, o una lista adicional de propiedades, y que no especificarlas por defecto es un valor no vacío, mientras que especificar la cadena vacía debería hacer que el script use una extensión vacía o una lista de propiedades adicionales.

Sin embargo, la distinción puede no ser esencial en todos los escenarios. En esos casos [ -z "$var" ] estará bien.

 1678
Author: Lionel,
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
2018-06-15 18:39:20

Para verificar la variable de cadena no nula/no nula, es decir, si se establece, use

if [ -n "$1" ]

Es lo contrario de -z. Me encuentro usando -n más que -z.

 676
Author: mbrannig,
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
2013-10-13 15:42:36

He aquí cómo probar si un parámetro está sin establecer , o vacío ("nulo") o establecido con un valor :

+--------------------+----------------------+-----------------+-----------------+
|                    |       parameter      |     parameter   |    parameter    |
|                    |   Set and Not Null   |   Set But Null  |      Unset      |
+--------------------+----------------------+-----------------+-----------------+
| ${parameter:-word} | substitute parameter | substitute word | substitute word |
| ${parameter-word}  | substitute parameter | substitute null | substitute word |
| ${parameter:=word} | substitute parameter | assign word     | assign word     |
| ${parameter=word}  | substitute parameter | substitute null | assign word     |
| ${parameter:?word} | substitute parameter | error, exit     | error, exit     |
| ${parameter?word}  | substitute parameter | substitute null | error, exit     |
| ${parameter:+word} | substitute word      | substitute null | substitute null |
| ${parameter+word}  | substitute word      | substitute word | substitute null |
+--------------------+----------------------+-----------------+-----------------+

Fuente: POSIX: Expansión de parámetros :

En todos los casos que se muestran con "sustituir", la expresión se sustituye por el valor que se muestra. En todos los casos mostrados con "assign", al parámetro se le asigna ese valor, que también reemplaza la expresión.

 400
Author: Jens,
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
2016-08-11 17:19:35

Hay muchas maneras de hacer esto con la siguiente siendo una de ellas:

if [ -z "$1" ]

Esto tiene éxito si $1 es null o unset

 168
Author: ennuikiller,
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
2016-03-07 22:55:45

Mientras que la mayoría de las técnicas indicadas aquí son correctas, bash 4.2 soporta una prueba real para la presencia de una variable ( man bash), en lugar de probar el valor de la variable.

[[ -v foo ]]; echo $?
# 1

foo=bar
[[ -v foo ]]; echo $?
# 0

foo=""
[[ -v foo ]]; echo $?
# 0
 154
Author: Russell Harmon,
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
2017-03-11 19:46:43

Para ver si una variable no está vacía, utilizo

if [[ $var ]]; then ...       # `$var' expands to a nonempty string

Las pruebas opuestas si una variable está desajustada o vacía:

if [[ ! $var ]]; then ...     # `$var' expands to the empty string (set or not)

Para ver si se establece una variable (vacía o no vacía), utilizo

if [[ ${var+x} ]]; then ...   # `var' exists (empty or nonempty)
if [[ ${1+x} ]]; then ...     # Parameter 1 exists (empty or nonempty)

Las pruebas opuestas si una variable no está establecida:

if [[ ! ${var+x} ]]; then ... # `var' is not set at all
if [[ ! ${1+x} ]]; then ...   # We were called with no arguments
 57
Author: phkoester,
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
2013-05-08 08:32:46

Siempre encuentro la tabla POSIX en la otra respuesta lento para grok, así que aquí está mi opinión sobre ella:

   +----------------------+------------+-----------------------+-----------------------+
   |   if VARIABLE is:    |    set     |         empty         |        unset          |
   +----------------------+------------+-----------------------+-----------------------+
 - |  ${VARIABLE-default} | $VARIABLE  |          ""           |       "default"       |
 = |  ${VARIABLE=default} | $VARIABLE  |          ""           | $(VARIABLE="default") |
 ? |  ${VARIABLE?default} | $VARIABLE  |          ""           |       exit 127        |
 + |  ${VARIABLE+default} | "default"  |       "default"       |          ""           |
   +----------------------+------------+-----------------------+-----------------------+
:- | ${VARIABLE:-default} | $VARIABLE  |       "default"       |       "default"       |
:= | ${VARIABLE:=default} | $VARIABLE  | $(VARIABLE="default") | $(VARIABLE="default") |
:? | ${VARIABLE:?default} | $VARIABLE  |       exit 127        |       exit 127        |
:+ | ${VARIABLE:+default} | "default"  |          ""           |          ""           |
   +----------------------+------------+-----------------------+-----------------------+

Tenga en cuenta que cada grupo (con y sin dos puntos anteriores) tiene los mismos casos establecidosy no establecidos, por lo que lo único que difiere es cómo se manejan los casos vacíos.

Con los dos puntos anteriores, los vacíos y desajustados casos son idénticos, por lo que usaría esos siempre que sea posible (es decir, use :=, no solo =, porque el caso vacío es inconsistente).

De la rúbrica:

  • set significa VARIABLE no está vacío (VARIABLE="something")
  • empty significa {[3] } es empty / null (VARIABLE="")
  • unset significa VARIABLE no existe (unset VARIABLE)

Valores:

  • $VARIABLE significa que el resultado es el valor original de la variable.
  • "default" significa que el resultado fue la cadena de reemplazo proporcionada.
  • "" significa el resultado es null (una cadena vacía).
  • exit 127 significa que el script deja de ejecutarse con el código de salida 127.
  • $(VARIABLE="default") significa que el resultado es el valor original de la variable y la cadena de reemplazo proporcionada se asigna a la variable para uso futuro.
 37
Author: deizel,
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
2017-08-24 16:48:20

En una versión moderna de Bash (4.2 o posterior, creo; no lo sé con seguridad), probaría esto:

if [ ! -v SOMEVARIABLE ] #note the lack of a $ sigil
then
    echo "Variable is unset"
elif [ -z "$SOMEVARIABLE" ]
then
    echo "Variable is set to an empty string"
else
    echo "Variable is set to some string"
fi
 31
Author: Seamus Connor,
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
2015-11-10 16:02:25
if [ "$1" != "" ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

Aunque para los argumentos normalmente es mejor probar $#, que es el número de argumentos, en mi opinión.

if [ $# -gt 0 ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi
 18
Author: Paul Creasey,
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
2010-08-30 16:43:46

Lea la sección "Expansión de parámetros" de la página de manual de bash. La expansión de parámetros no proporciona una prueba general para una variable que se está estableciendo, pero hay varias cosas que puede hacer a un parámetro si no está establecido.

Por ejemplo:

function a {
    first_arg=${1-foo}
    # rest of the function
}

Establecerá first_arg igual a $1 si se asigna, de lo contrario utiliza el valor "foo". Si a absolutamente debe tomar un solo parámetro, y no existe un buen valor predeterminado, puede salir con un mensaje de error cuando no hay parámetro dado:

function a {
    : ${1?a must take a single argument}
    # rest of the function
}

(Tenga en cuenta el uso de : como un comando null, que solo expande los valores de sus argumentos. No queremos hacer nada con $1 en este ejemplo, solo salir si no está configurado)

 14
Author: chepner,
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-01-31 22:05:06

Desea salir si no está configurado

Esto funcionó para mí. Quería que mi script saliera con un mensaje de error si no se había establecido un parámetro.

#!/usr/bin/env bash

set -o errexit

# Get the value and empty validation check all in one
VER="${1:?You must pass a version of the format 0.0.0 as the only argument}"

Esto regresa con un error cuando se ejecuta

peek@peek:~$ ./setver.sh
./setver.sh: line 13: 1: You must pass a version of the format 0.0.0 as the only argument

Solo marque, sin salida: Vacío y sin configurar no son VÁLIDOS

Pruebe esta opción si solo desea comprobar si el valor set=VALID o unset/empty=INVALID.

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID
if [ "${TUNSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

O, Incluso, pruebas cortas; -)

[ "${TSET:-}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY:-}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET:-}" ] && echo "VALID" || echo "INVALID"

Solo marque, sin salida-Solo vacío no es VÁLIDO

Y esto es la respuesta a la pregunta. Use esto si solo desea comprobar si el valor set/empty=VALID o unset=INVALID.

NOTA, el "1" en "..-1}" es insignificante, puede ser cualquier cosa (como x)

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TUNSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

Pruebas cortas

[ "${TSET+1}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY+1}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET+1}" ] && echo "VALID" || echo "INVALID"

Dedico esta respuesta a @mklement0 (comentarios) quien me desafió a responder la pregunta con precisión.

Referencia http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02

 14
Author: Jarrod Chesney,
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
2016-12-16 04:46:12

Para comprobar si una variable está configurada con un valor no vacío, utilice [ -n "$x" ], como ya han indicado otros.

La mayoría de las veces, es una buena idea tratar una variable que tiene un valor vacío de la misma manera que una variable que no está establecida. Pero puedes distinguir los dos si necesitas: [ -n "${x+set}" ] ("${x+set}" se expande a set si x está establecido y a la cadena vacía si x no está establecido).

Para comprobar si se ha pasado un parámetro, pruebe $#, que es el número de parámetros pasados a la función (o al script, cuando no está en una función) (ver La respuesta de Pablo).

 12
Author: Gilles,
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
2017-05-23 12:34:53

En bash puedes usar -v dentro del [[ ]] incorporado:

#! /bin/bash -u

if [[ ! -v SOMEVAR ]]; then
    SOMEVAR='hello'
fi

echo $SOMEVAR
 10
Author: AlejandroVD,
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
2016-03-28 21:13:34

Para aquellos que buscan comprobar si no está configurado o está vacío cuando está en un script con set -u:

if [ -z "${var-}" ]; then
   echo "Must provide var environment variable. Exiting...."
   exit 1
fi

Regular [ -z "$var" ] verificación fallará con var; unbound variable si set -u pero [ -z "${var-}" ] expande a cadena vacía si var no está definida, sin fallar.

 9
Author: ecerulm,
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
2016-11-16 11:26:13

Puedes hacer:

function a {
        if [ ! -z "$1" ]; then
                echo '$1 is set'
        fi
}
 4
Author: codaddict,
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
2010-08-31 07:23:26

Las respuestas anteriores no funcionan cuando la opción Bash set -u está habilitada. Además, no son dinámicos, por ejemplo, ¿cómo probar es variable con el nombre "dummy" se define? Prueba esto:

is_var_defined()
{
    if [ $# -ne 1 ]
    then
        echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
        exit 1
    fi
    # Tricky.  Since Bash option 'set -u' may be enabled, we cannot directly test if a variable
    # is defined with this construct: [ ! -z "$var" ].  Instead, we must use default value
    # substitution with this construct: [ ! -z "${var:-}" ].  Normally, a default value follows the
    # operator ':-', but here we leave it blank for empty (null) string.  Finally, we need to
    # substitute the text from $1 as 'var'.  This is not allowed directly in Bash with this
    # construct: [ ! -z "${$1:-}" ].  We need to use indirection with eval operator.
    # Example: $1="var"
    # Expansion for eval operator: "[ ! -z \${$1:-} ]" -> "[ ! -z \${var:-} ]"
    # Code  execute: [ ! -z ${var:-} ]
    eval "[ ! -z \${$1:-} ]"
    return $?  # Pedantic.
}

Relacionado: En Bash, ¿cómo pruebo si una variable está definida en modo" - u "

 4
Author: kevinarpe,
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
2017-05-23 12:18:27

Usar [[ -z "$var" ]] es la forma más fácil de saber si una variable se estableció o no, pero esa opción -z no distingue entre una variable sin establecer y una variable establecida en una cadena vacía:

$ set=''
$ [[ -z "$set" ]] && echo "Set" || echo "Unset" 
Unset
$ [[ -z "$unset" ]] && echo "Set" || echo "Unset"
Unset

Lo mejor es comprobarlo según el tipo de variable: variable env, parámetro o variable regular.

Para una variable env:

[[ $(env | grep "varname=" | wc -l) -eq 1 ]] && echo "Set" || echo "Unset"

Para un parámetro (por ejemplo, para comprobar la existencia de parámetro $5):

[[ $# -ge 5 ]] && echo "Set" || echo "Unset"

Para una variable regular (usando un auxiliar función, para hacerlo de una manera elegante):

function declare_var {
   declare -p "$1" &> /dev/null
   return $?
}
declare_var "var_name" && echo "Set" || echo "Unset"

Notas:

  • $#: dice que el número de parámetros posicionales.
  • declare -p: le da la definición de la variable pasada como parámetro. Si existe, devuelve 0, si no, devuelve 1 e imprime un mensaje de error.
  • $?: le da el código de estado del último comando ejecutado.
 2
Author: Peregring-lk,
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
2018-07-10 08:10:51

En un shell puedes usar el operador -z que es True si la longitud de la cadena es cero.

Una simple línea para establecer por defecto MY_VAR si no está establecido, de lo contrario opcionalmente puede mostrar el mensaje:

[[ -z "$MY_VAR" ]] && MY_VAR="default"
[[ -z "$MY_VAR" ]] && MY_VAR="default" || echo "Variable already set."
 1
Author: kenorb,
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
2015-11-10 16:04:12

Mi camino preferido es este:

$var=10
$if ! ${var+false};then echo "is set";else echo "NOT set";fi
is set
$unset var
$if ! ${var+false};then echo "is set";else echo "NOT set";fi
NOT set

Así que básicamente, si una variable se establece, se convierte en "una negación del resultado false" (lo que será true = "se establece").

Y, si no está configurado, se convertirá en "una negación del resultado true" (ya que el resultado vacío se evalúa como true) (por lo que terminará como false = "NO establecido").

 1
Author: Aquarius Power,
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
2015-11-10 16:05:00
if [[ ${1:+isset} ]]
then echo "It was set and not null." >&2
else echo "It was not set or it was null." >&2
fi

if [[ ${1+isset} ]]
then echo "It was set but might be null." >&2
else echo "It was was not set." >&2
fi
 0
Author: solidsnack,
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
2013-06-30 05:22:39

He encontrado un código (mucho) mejor para hacer esto si quieres comprobar algo en $@.

if [[ $1 = "" ]]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi

¿Por qué todo esto? Todo en $@ existe en Bash, pero por defecto está en blanco, así que test -z y test -n no podrían ayudarte.

Actualizar: También puede contar el número de caracteres en un parámetro.

if [ ${#1} = 0 ]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi
 0
Author: Zlatan,
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
2013-12-27 16:30:37
[[ $foo ]]

O

(( ${#foo} ))

O

let ${#foo}

O

declare -p foo
 0
Author: Steven Penny,
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
2014-05-11 05:43:17
if [[ ${!xx[@]} ]] ; then echo xx is defined; fi
 0
Author: Graham,
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
2015-08-12 18:43:56

Siempre uso este, basado en el hecho de que parece fácil de ser entendido por cualquiera que vea el código por primera vez:

if [ "$variable" = "" ]
    then
    echo "Variable X is empty"
fi

Y, si quiere comprobar si no está vacío;

if [ ! "$variable" = "" ]
    then
    echo "Variable X is not empty"
fi

Eso es todo.

 0
Author: mijnnaam,
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
2015-11-10 16:03:35

Esto es lo que uso todos los días:

#
# Check if a variable is set
#   param1  name of the variable
#
function is_set()
{
    [[ -n "${1}" ]] && test -n "$(eval "echo "\${${1}+x}"")"
}

Esto funciona bien bajo Linux y Solaris hasta bash 3.0.

bash-3.00$ myvar="TEST"
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ mavar=""
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ unset myvar
bash-3.00$ is_set myvar ; echo $?
1
 0
Author: fr00tyl00p,
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
2015-11-10 16:06:00

Si var puede ser una matriz, entonces [ -z "${var+x}" ] la sustitución de parámetros es incorrecta. Para estar realmente seguro en Bash necesita usar sintaxis de matriz como [ "${#var[@]}" = 0 ], como se muestra a continuación.

is-var-set () {
    results="\${var+x}=${var+x}\t\${#var[@]}=${#var[@]}"
    if [ -z "${var+x}" ] && [ "${#var[@]}" = 0 ]; then
        echo -e "$1: var's unset.\t$results"
    elif [ -n "${var+x}" ] && [ "${#var[@]}" != 0 ]; then
        echo -e "$1: var is set. \t$results"
    else
        echo -e "$1: Is var set? \t$results"
    fi
    unset var # so we don't have to do it everywhere else
}

En casi todos los casos, están de acuerdo. La única situación que he encontrado donde el método array es más preciso es cuando la variable es un array no vacío con position 0 unset (por ejemplo, en tests 7 y A más abajo). Este desacuerdo viene de $var siendo la abreviatura de ${var[0]}, por lo que [ -z "${var+x}" ] no está comprobando la todo el arsenal.

Aquí están mis casos de prueba.

unset var;      is-var-set 1 # var unset
var='';         is-var-set 2 # var[0] set to ''
var=foo;        is-var-set 3 # var[0] set to 'foo'
var=();         is-var-set 4 # var unset (all indices)
var=(foo);      is-var-set 5 # var[0] set to 'foo'
var=([0]=foo);  is-var-set 6 # var[0] set to 'foo'
var=([1]=foo);  is-var-set 7 # var[0] unset, but var[1] set to 'foo'
declare -a var; is-var-set 8 # var empty, but declared as an array
declare -A var; is-var-set 9 # var empty, but declared as an associative array
declare -A var  # Because is-var-set() conveniently unsets it
var=([xz]=foo); is-var-set A # var[xz] set to 'foo', but var's otherwise empty
declare -a var  # Demonstrate that Bash knows about var, even when there's
declare -A var; is-var-set B # apparently no way to just _check_ its existence

Aquí está la salida.

1: var's unset. ${var+x}=       ${#var[@]}=0
2: var is set.  ${var+x}=x      ${#var[@]}=1
3: var is set.  ${var+x}=x      ${#var[@]}=1
4: var's unset. ${var+x}=       ${#var[@]}=0
5: var is set.  ${var+x}=x      ${#var[@]}=1
6: var is set.  ${var+x}=x      ${#var[@]}=1
7: Is var set?  ${var+x}=       ${#var[@]}=1
8: var's unset. ${var+x}=       ${#var[@]}=0
9: var's unset. ${var+x}=       ${#var[@]}=0
A: Is var set?  ${var+x}=       ${#var[@]}=1
./foo.sh: line 26: declare: var: cannot convert indexed to associative array
B: var's unset. ${var+x}=       ${#var[@]}=0

En suma:

  • ${var+x} la sintaxis de expansión de parámetros funciona tan bien como la sintaxis de matriz ${#var[@]} en la mayoría de los casos, como la comprobación de parámetros a funciones. La única forma en que este caso podría romperse es si una versión futura de Bash agrega una forma de pasar matrices a funciones sin convertir el contenido en argumentos individuales.
  • Se requiere sintaxis de matriz para matrices no vacías (asociativo o no) con elemento 0 unset.
  • Ninguna sintaxis explica lo que está pasando si declare -a var se ha utilizado sin asignar ni siquiera un valor null en algún lugar de la matriz. Bash todavía distingue el caso en alguna parte (como se ve en test B arriba), por lo que esta respuesta no es infalible. Afortunadamente, Bash convierte las variables de entorno exportadas en cadenas cuando se ejecuta un programa / script, por lo que cualquier problema con las variables declaradas pero no establecidas se contendrá en un solo script, al menos si no aprovisionamiento de otros scripts.
 0
Author: Mark Haferkamp,
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
2016-02-15 14:32:17

Si desea probar que una variable está enlazada o no, esto funciona bien, incluso después de haber activado la opción nounset:

set -o noun set

if printenv variableName >/dev/null; then
    # variable is bound to a value
else
    # variable is unbound
fi
 -1
Author: user1857592,
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
2013-05-25 20:08:04

Me gustan las funciones auxiliares para ocultar los detalles crudos de bash. En este caso, hacerlo añade aún más crudeza (oculta):

# The first ! negates the result (can't use -n to achieve this)
# the second ! expands the content of varname (can't do ${$varname})
function IsDeclared_Tricky
{
  local varname="$1"
  ! [ -z ${!varname+x} ]
}

Debido a que primero tuve errores en esta implementación (inspirado por las respuestas de Jens y Lionel), se me ocurrió una solución diferente:

# Ask for the properties of the variable - fails if not declared
function IsDeclared()
{
  declare -p $1 &>/dev/null
}

Encuentro que es más sencillo, más grosero y más fácil de entender/recordar. El caso de prueba muestra que es equivalente:

function main()
{
  declare -i xyz
  local foo
  local bar=
  local baz=''

  IsDeclared_Tricky xyz; echo "IsDeclared_Tricky xyz: $?"
  IsDeclared_Tricky foo; echo "IsDeclared_Tricky foo: $?"
  IsDeclared_Tricky bar; echo "IsDeclared_Tricky bar: $?"
  IsDeclared_Tricky baz; echo "IsDeclared_Tricky baz: $?"

  IsDeclared xyz; echo "IsDeclared xyz: $?"
  IsDeclared foo; echo "IsDeclared foo: $?"
  IsDeclared bar; echo "IsDeclared bar: $?"
  IsDeclared baz; echo "IsDeclared baz: $?"
}

main

El caso de prueba también muestra que local var hace NO declarar var (a menos que vaya seguido de '='). Durante bastante tiempo pensé que declaraba variables de esta manera, solo para descubrir ahora que simplemente expresaba mi intención... Es un no-op, supongo.

IsDeclared_Tricky xyz: 1
IsDeclared_Tricky foo: 1
IsDeclared_Tricky bar: 0
IsDeclared_Tricky baz: 0
IsDeclared xyz: 1
Es declarado foo: 1
IsDeclared bar: 0
IsDeclared baz: 0

BONO: usecase

Utilizo principalmente esto prueba para dar (y devolver) parámetros a las funciones de una manera algo "elegante" y segura (casi se asemeja a una interfaz...):

#auxiliary functions
function die()
{
  echo "Error: $1"; exit 1
}

function assertVariableDeclared()
{
  IsDeclared "$1" || die "variable not declared: $1"
}

function expectVariables()
{
  while (( $# > 0 )); do
    assertVariableDeclared $1; shift
  done
}

# actual example
function exampleFunction()
{
  expectVariables inputStr outputStr
  outputStr="$inputStr world!"
}

function bonus()
{
  local inputStr='Hello'
  local outputStr= # remove this to trigger error
  exampleFunction
  echo $outputStr
}

bonus

Si se llama con todas las variables requires declaradas:

Hola mundo!

Else:

Error: variable no declarada: outputStr

 -1
Author: Daniel S,
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
2016-03-01 13:23:29

Funciones para comprobar si la variable está declarada/desajustada

Incluido vacío $array=()


Las siguientes funciones prueban si el nombre dado existe como variable

# The first parameter needs to be the name of the variable to be checked.
# (See example below)

var_is_declared() {
    { [[ -n ${!1+anything} ]] || declare -p $1 &>/dev/null;}
}

var_is_unset() {
    { [[ -z ${!1+anything} ]] && ! declare -p $1 &>/dev/null;} 
}
  • Al probar primero si la variable está (des)establecida, se puede evitar la llamada a declarar, si no es necesario.
  • Si sin embargo $1 contiene el nombre de un $array=() vacío, la llamada a declarar se aseguraría de obtener el resultado correcto
  • Nunca hay muchos datos pasados a / dev / null como declare es solo se llama si la variable no está establecida o si es una matriz vacía.

Estas funciones probarían como se muestra en las siguientes condiciones:

a;       # is not declared
a=;      # is declared
a="foo"; # is declared
a=();    # is declared
a=("");  # is declared
unset a; # is not declared

a;       # is unset
a=;      # is not unset
a="foo"; # is not unset
a=();    # is not unset
a=("");  # is not unset
unset a; # is unset

.

Para más detalles

Y un script de prueba ver mi respuesta a la pregunta "¿Cómo compruebo si existe una variable en bash?".

Observación: El uso similar de declare -p, como también se muestra en Peregring-lk 's respuesta , es realmente coincidencia. ¡De lo contrario, por supuesto, lo habría acreditado!

 -1
Author: Martin Rüegg,
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
2017-05-23 11:55:03
case "$1" in
 "") echo "blank";;
 *) echo "set"
esac
 -2
Author: ghostdog74,
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
2010-08-30 15:32:16