bash - programacion - scripts linux ejercicios resueltos
¿Cómo saber si una cadena no está definida en un script de shell bash? (11)
Aquí está lo que creo que es una forma mucho más clara de verificar si una variable está definida:
var_defined() {
local var_name=$1
set | grep "^${var_name}=" 1>/dev/null
return $?
}
Úselo de la siguiente manera:
if var_defined foo; then
echo "foo is defined"
else
echo "foo is not defined"
fi
Si quiero verificar la cadena nula lo haría
[ -z $mystr ]
pero, ¿qué ocurre si quiero verificar si la variable se ha definido? ¿O no hay distinción en los scripts bash?
Creo que la respuesta que buscas está implícita (si no está indicada) en la answer Vinko , aunque no está explicada de manera simple. Para distinguir si VAR está configurado pero vacío o no configurado, puede usar:
if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi
Probablemente pueda combinar las dos pruebas en la segunda línea en una con:
if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi
Sin embargo, si lee la documentación de Autoconf, encontrará que no recomiendan combinar los términos con '' -a
'' y sí recomiendan usar pruebas simples separadas combinadas con &&
. No he encontrado un sistema donde haya un problema; eso no quiere decir que no solían existir (pero probablemente sean extremadamente raros actualmente, incluso si no fueran tan raros en el pasado distante).
Puede encontrar los detalles de estas y otras expansiones de parámetros de shell relacionadas, la test
o [
comando y expresiones condicionales en el manual de Bash.
Hace poco me preguntaron por correo electrónico sobre esta respuesta con la pregunta:
Usas dos pruebas, y entiendo bien el segundo, pero no el primero. Más precisamente, no entiendo la necesidad de una expansión variable
if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
¿No lograría esto lo mismo?
if [ -z "${VAR}" ]; then echo VAR is not set at all; fi
Pregunta justa: la respuesta es ''No, su alternativa más simple no hace lo mismo''.
Supongamos que escribo esto antes de su prueba:
VAR=
Su prueba dirá "VAR no está configurado para nada", pero la mía dirá (por implicación, porque no hace eco de nada) "VAR está configurado, pero su valor puede estar vacío". Prueba este script:
(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi
if [ -z "${VAR}" ]; then echo MP:1 VAR is not set at all; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi
if [ -z "${VAR}" ]; then echo MP:2 VAR is not set at all; fi
)
El resultado es:
JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all
En el segundo par de pruebas, la variable se establece, pero se establece en el valor vacío. Esta es la distinción que hacen las anotaciones ${VAR=value}
y ${VAR:=value}
. Lo mismo para ${VAR-value}
y ${VAR:-value}
, y ${VAR+value}
y ${VAR:+value}
, y así sucesivamente.
Como señala Gili en su answer , si ejecuta bash
con la opción set -o nounset
, entonces la respuesta básica anterior falla con la unbound variable
. Se remedia fácilmente:
if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi
O puede cancelar la opción set -o nounset
con set +u
( set -u
es equivalente a set -o nounset
).
El Manual de referencia de Bash es una fuente autorizada de información sobre bash.
Aquí hay un ejemplo de prueba de una variable para ver si existe:
if [ -z "$PS1" ]; then
echo This shell is not interactive
else
echo This shell is interactive
fi
(De la sección 6.3.2 )
Tenga en cuenta que el espacio en blanco después de abrir [
y antes de ]
no es opcional .
Consejos para usuarios de Vim
Tenía un script que tenía varias declaraciones de la siguiente manera:
export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
Pero quería que difirieran a cualquier valor existente. Así que los re-escribí para que se vean así:
if [ -z "$VARIABLE_NAME" ]; then
export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
fi
Pude automatizar esto en vim usando una expresión regular rápida:
s//vexport ([A-Z_]+)/=("[^"]+")/n/if [ -z "$/1" ]; then/r export /1=/2/rfi/r/gc
Esto se puede aplicar seleccionando las líneas relevantes visualmente y luego escribiendo :
La barra de comandos se rellena previamente con :''<,''>
. Pega el comando de arriba y presiona enter.
Probado en esta versión de Vim:
VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58)
Compiled by [email protected]
Los usuarios de Windows pueden desear finales de línea diferentes.
Guía avanzada de scripts de bash, 10.2. Sustitución de parámetros:
- $ {var + blahblah}: si se define var, ''blahblah'' se sustituye por la expresión, else null se sustituye
- $ {var-blahblah}: si se define var, se sustituye a sí mismo, sino que se sustituye ''blahblah''
- $ {var? blahblah}: si se define var, se sustituye, de lo contrario la función existe con ''blahblah'' como un mensaje de error.
para basar su lógica de programa en si la variable $ mystr está definida o no, puede hacer lo siguiente:
isdefined=0
${mystr+ export isdefined=1}
ahora, si isdefined = 0, entonces la variable no estaba definida, si isdefined = 1 la variable estaba definida
Esta forma de comprobar variables es mejor que la respuesta anterior porque es más elegante, legible, y si su shell bash se configuró para error en el uso de variables indefinidas (set -u)
, el script terminará prematuramente.
Otras cosas útiles:
tener un valor predeterminado de 7 asignado a $ mystr si no está definido, y dejarlo intacto si no:
mystr=${mystr- 7}
para imprimir un mensaje de error y salir de la función si la variable no está definida:
: ${mystr? not defined}
Tenga cuidado aquí que utilicé '':'' para no tener el contenido de $ mystr ejecutado como un comando en caso de que esté definido.
La forma explícita de verificar una variable que se está definiendo sería:
[ -v mystr ]
Un resumen de pruebas.
[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set" # may or may not be empty
[ -n "${var+x}" ] && echo "var is set" # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"
conjunto de llamadas sin ningún argumento .. emite todos los valores definidos.
los últimos en la lista serían los definidos en tu script.
para que pueda canalizar su salida a algo que pueda descubrir qué cosas se definen y qué no
no arrojar esta bicicleta aún más, pero quería agregar
shopt -s -o nounset
es algo que podría agregarse a la parte superior de un script, que generará un error si las variables no se declaran en ningún lugar del script. El mensaje que vería es una unbound variable
, pero como otros lo mencionan, no detectará una cadena vacía o un valor nulo. Para garantizar que ningún valor individual no esté vacío, podemos probar una variable a medida que se expande con ${mystr:?}
, también conocida como expansión de signo de dólar, lo que generaría un error con el parameter null or not set
.
otra opción: la expansión de "lista de índices de matrices" :
$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1
la única vez que esto se expande a la cadena vacía es cuando foo
está desarmado, por lo que puedes verificarlo con la cadena condicional:
$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0
debería estar disponible en cualquier versión de bash> = 3.0
https://.com/a/9824943/14731 contiene una mejor respuesta (una que es más legible y funciona con set -o nounset
habilitado). Funciona más o menos así:
if [ -n "${VAR-}" ]; then
echo "VAR is set and is not empty"
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
echo "VAR is set, but empty"
else
echo "VAR is not set"
fi
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~>
-z también funciona para variables indefinidas. Para distinguir entre un indefinido y uno definido, usaría las cosas que se enumeran here o, con explicaciones más claras, here .
La forma más limpia es usar expansión como en estos ejemplos. Para obtener todas sus opciones, consulte la sección Expansión de parámetros del manual.
Palabra alternativa:
~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED
Valor por defecto:
~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED
Por supuesto, usaría uno de estos de manera diferente, poniendo el valor que desea en lugar de ''valor predeterminado'' y utilizando la expansión directamente, si corresponde.