scripts - variables en bash




¿Cómo comprobar si una variable está configurada en Bash? (20)

¿Cómo puedo saber si una variable está configurada en Bash?

Por ejemplo, ¿cómo verifico si el usuario asignó el primer parámetro a una función?

function a {
    # if $1 is set ?
}

Funciones para comprobar si la variable está declarada / desarmada

incluyendo vacio $array=()


Las siguientes funciones prueban si el nombre dado existe como una 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) configurada, la llamada a declarar se puede evitar, si no es necesario.
  • Sin embargo, si $1contiene el nombre de un vacío $array=(), la llamada a declarar se asegurará de que obtengamos el resultado correcto
  • Nunca se pasan muchos datos a / dev / null, ya que declarar solo se llama si la variable no está establecida o si es una matriz vacía.

Estas funciones se 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 vea mi answer a la pregunta "¿Cómo verifico si existe una variable en bash?" .

Observación: El uso similar de declare -p, como también se muestra en la answer , es una verdadera coincidencia. De lo contrario, por supuesto, lo habría acreditado!answer


(Generalmente) El camino correcto

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ámetros que no se evalúa en nada si var está establecida, y sustituye la cadena x caso contrario.

Cotizaciones de digresión

Se pueden omitir las cotizaciones (por lo que podemos decir ${var+x} lugar de "${var+x}" ) porque esta sintaxis y uso garantiza que solo se expandirá a algo que no requiere comillas (ya que se expande a x (que no contiene saltos de palabras, por lo que no necesita comillas), o nada (lo que da como resultado [ -z ] , que convenientemente evalúa al mismo valor (verdadero) que [ -z "" ] hace)).

Sin embargo, aunque las citas se pueden omitir de forma segura, y no fue inmediatamente obvio para todos (ni siquiera fue evidente para el primer autor de esta explicación de las citas, que también es un importante programador de Bash), a veces sería mejor escribir la solución con comillas como [ -z "${var+x}" ] , al muy bajo costo posible de una penalización de velocidad O (1). El primer autor también agregó esto como un comentario al lado del código que usa esta solución y proporciona la URL a esta respuesta, que ahora también incluye la explicación de por qué las citas 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 suele ser incorrecto porque no distingue entre una variable que no está establecida y una variable que se establece 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 "establecer en la cadena vacía" es esencial en situaciones en las que el usuario tiene que especificar una extensión, o una lista adicional de propiedades, y que al no especificarlas por defecto en un valor no vacío, mientras que la especificación de la cadena vacía debería haga 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.


A continuación, se explica cómo probar si un parámetro no está establecido, está vacío ("Nulo") o se establece 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 mostrados con "sustituto", la expresión se reemplaza con el valor mostrado. En todos los casos mostrados con "asignar", a ese parámetro se le asigna ese valor, que también reemplaza la expresión.


En bash puedes usar -v dentro de la [[ ]] incorporada:

#! /bin/bash -u

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

echo $SOMEVAR

En una versión moderna de Bash (4.2 o posterior, creo; no lo sé con seguridad), intentarí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

Encontré un código (mucho) mejor para hacer esto si quieres verificar algo en [email protected] .

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

¿Por qué todo esto? Todo en [email protected] existe en Bash, pero por defecto está en blanco, por lo que test -z y test -n no pudieron ayudarte.

Actualización: 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

Hay muchas formas de hacer esto con una de las siguientes:

if [ -z "$1" ]

Esto tiene éxito si $ 1 es nulo o no está configurado


Las respuestas anteriores no funcionan cuando Bash option set -u está habilitado. Además, no son dinámicos, por ejemplo, ¿cómo se determina si la variable de prueba con el nombre "ficticio" está definida? 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 puedo probar si una variable está definida en modo "-u"?


Mi forma preferida es esta:

$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

Entonces, básicamente, si se establece una variable, se convierte en "una negación de la false resultante" (lo que será true = "se establece").

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


Para aquellos que buscan verificar si no están configurados o están vacíos en un script con set -u :

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

La verificación regular [ -z "$var" ] fallará con var; unbound variable var; unbound variable si se set -u pero [ -z "${var-}" ] expands a una cadena vacía si var se establece sin error.


Para verificar la variable de cadena que no sea nula / no cero, es decir, si está establecida, use

if [ -n "$1" ]

Es lo opuesto a -z . Me encuentro usando -n más que -z .


Para verificar si una variable está configurada con un valor no vacío, use [ -n "$x" ] , como ya indicaron 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 puede distinguir los dos si necesita: [ -n "${x+set}" ] ( "${x+set}" expande para set si x está establecido y para la cadena vacía si x está establecida).

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


Si bien la mayoría de las técnicas que se indican aquí son correctas, bash 4.2 admite una prueba real de 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

Siempre encuentro que la tabla POSIX en la otra respuesta es lenta a la de los otros , así que aquí está mi opinión:

   +----------------------+------------+-----------------------+-----------------------+
   |   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 los dos puntos anteriores) tiene los mismos casos establecidos y no configurados , por lo que lo único que difiere es cómo se manejan los casos vacíos .

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

Encabezados:

  • set significa que VARIABLE no está vacío ( VARIABLE="something" )
  • vacío significa VARIABLE está vacío / nulo ( VARIABLE="" )
  • unset significa que 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 que el resultado es nulo (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 provista se asigna a la variable para uso futuro.

Tu puedes hacer:

function a {
        if [ ! -z "$1" ]; then
                echo '$1 is set'
        fi
}

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 no establecida y una variable establecida en una cadena vacía:

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

Es mejor verificarlo de acuerdo con 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 verificar la existencia del parámetro $5 ):

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

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

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

Notas:

  • $# : te dice 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.

Me gustan las funciones auxiliares para ocultar los detalles crudos de bash. En este caso, hacerlo agrega 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} ]
}

Como primero tuve errores en esta implementación (inspirada en 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
}

Me parece que es más sencillo, más aburrido 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 varno NO declarar var (a menos que seguido por '='). Durante bastante tiempo pensé que había declarado las variables de esta manera, solo para descubrir ahora que simplemente expresé mi intención ... Supongo que es una no operación.

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

BONIFICACIÓN: Usecase

Principalmente utilizo esta prueba para dar (y devolver) parámetros a las funciones de una manera "elegante" y segura (casi parecida 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 requeridas declaradas:

¡Hola Mundo!

más:

Error: variable no declarada: outputStr


[[ $foo ]]

O

(( ${#foo} ))

O

let ${#foo}

O

declare -p foo

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

if [[ ${!xx[@]} ]] ; then echo xx is defined; fi




variables