He estado mirando algunos scripts que otras personas escribieron (específicamente Red Hat), y muchas de sus variables se asignan usando la siguiente notación VARIABLE1="${VARIABLE1:-some_val}"
o algunas expandir otras variables VARIABLE2="${VARIABLE2:-`echo $VARIABLE1`}"
¿Cuál es el punto de usar esta notación en lugar de simplemente declarar los valores directamente (por ejemplo, VARIABLE1=some_val
)?
¿Hay beneficios en esta notación o posibles errores que podrían evitarse?
¿Tiene :-
un significado específico en este contexto ?
Comentarios
Respuesta
Esta técnica permite asignar un valor a una variable si otra variable está vacía o no está definida. NOTA: Esta «otra variable» puede ser la misma u otra variable.
extracto
${parameter:-word} If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.
NOTA: Este El formulario también funciona, ${parameter-word}
. Si desea ver una lista completa de todas las formas de expansión de parámetros disponibles en Bash, le sugiero que eche un vistazo a este tema en la wiki de Bash Hacker titulado: « Expansión de parámetros «.
Ejemplos
variable no existe
$ echo "$VAR1" $ VAR1="${VAR1:-default value}" $ echo "$VAR1" default value
variable existe
$ VAR1="has value" $ echo "$VAR1" has value $ VAR1="${VAR1:-default value}" $ echo "$VAR1" has value
Se puede hacer lo mismo evaluando otras variables o ejecutando comandos dentro de la parte del valor predeterminado de la notación.
$ VAR2="has another value" $ echo "$VAR2" has another value $ echo "$VAR1" $ $ VAR1="${VAR1:-$VAR2}" $ echo "$VAR1" has another value
Más ejemplos
También puede usar una notación ligeramente diferente donde «es simplemente VARX=${VARX-<def. value>}
.
$ echo "${VAR1-0}" has another value $ echo "${VAR2-0}" has another value $ echo "${VAR3-0}" 0
En el $VAR1
& ya estaban definidos con la cadena «tiene otro valor» pero $VAR3
no estaba definido, por lo que se usó el valor predeterminado en su lugar, 0
.
Otro ejemplo
$ VARX="${VAR3-0}" $ echo "$VARX" 0
Verificación y asignación usando :=
notación
Por último, «mencionaré el operador útil, :=
. Esto hará una verificación y asignará un valor si la variable bajo prueba está vacía o no está definida.
Ejemplo
Observe que $VAR1
es ahora colocar. El operador :=
hizo la prueba y la asignación en una sola operación.
$ unset VAR1 $ echo "$VAR1" $ echo "${VAR1:=default}" default $ echo "$VAR1" default
Sin embargo, si el valor está establecido antes, luego se deja solo.
$ VAR1="some value" $ echo "${VAR1:=default}" some value $ echo "$VAR1" some value
Handy Dandy Reference Table
Referencias
- Expansiones de parámetros – Wiki de Bash Hackers
- 10.2. Sustitución de parámetros
- Expansiones de parámetros de Bash
Comentarios
- Tenga en cuenta que no todas estas expansiones están documentadas en
bash
. El${var:-word}
de Q es, pero no el${var-word}
anterior. El POSIX aunque la documentación tiene una buena tabla, podría valer la pena copiarla en th es la respuesta – pubs.opengroup.org/onlinepubs/9699919799/utilities/… - @Graeme, está documentado, solo necesita prestar atención a Omitir los dos puntos resulta en una prueba solo para un parámetro que no está establecido.
- Usando
echo "${FOO:=default}"
es genial si realmente quieresecho
. Pero si no ‘ t, pruebe el:
integrado …: ${FOO:=default}
Su$FOO
está configurado endefault
como se indicó anteriormente (es decir, si aún no lo ha configurado). Pero ‘ no se repite$FOO
en el proceso. - Ok, encontré una respuesta: stackoverflow.com / q / 24405606/1172302 . El uso de
${4:-$VAR}
funcionará. - +1 solo para obtener la respuesta detallada. Pero también por el hecho de que hace referencia a la excelente wiki de bash. Y también por el hecho de que das ejemplos y una tabla. Demonios, solo +1 en todo el camino hacia abajo 🙂 En cuanto a mí, casi tenía la sintaxis correcta, pero no del todo; simplemente no ‘ me importaba lo suficiente como para buscar en la página del manual pero no pude ‘ recordar en qué título estaba y ‘ he estado despierto desde las 4 de esta mañana :() ..
Respuesta
@slm ya ha incluido los documentos POSIX , que son muy útiles, pero en realidad no amplían la forma en que estos parámetros pueden combinarse para afectarse entre sí. Todavía no se menciona aquí esta forma:
${var?if unset parent shell dies and this message is output to stderr}
Este es un extracto de otra respuesta mía, y creo que demuestra muy bien cómo funcionan:
sh <<-\CMD _input_fn() { set -- "$@" #redundant echo ${*?WHERES MY DATA?} #echo is not necessary though shift #sure hope we have more than $1 parameter : ${*?WHERES MY DATA?} #: do nothing, gracefully } _input_fn heres some stuff _input_fn one #here # shell dies - third try doesnt run _input_fn you there? # END CMD heres some stuff one sh: line :5 *: WHERES MY DATA?
Otro ejemplo de igual :
sh <<-\CMD N= #N is NULL _test=$N #_test is also NULL and v="something you would rather do without" ( #this subshell dies echo "v is ${v+set}: and its value is ${v:+not NULL}" echo "So this ${_test:-"\$_test:="} will equal ${_test:="$v"}" ${_test:+${N:?so you test for it with a little nesting}} echo "sure wish we could do some other things" ) ( #this subshell does some other things unset v #to ensure it is definitely unset echo "But here v is ${v-unset}: ${v:+you certainly wont see this}" echo "So this ${_test:-"\$_test:="} will equal NULL ${_test:="$v"}" ${_test:+${N:?is never substituted}} echo "so now we can do some other things" ) #and even though we set _test and unset v in the subshell echo "_test is still ${_test:-"NULL"} and ${v:+"v is still $v"}" # END CMD v is set: and its value is not NULL So this $_test:= will equal something you would rather do without sh: line 7: N: so you test for it with a little nesting But here v is unset: So this $_test:= will equal NULL so now we can do some other things _test is still NULL and v is still something you would rather do without
El ejemplo anterior aprovecha las 4 formas de sustitución de parámetros POSIX y sus diversas :colon null
o not null
pruebas. Hay más información en el enlace anterior y aquí está de nuevo .
Otra cosa que la gente a menudo no considera acerca de ${parameter:+expansion}
es lo útil que puede ser en un documento aquí. Aquí hay otro extracto de un respuesta diferente :
ARRIBA
Aquí establecerá algunos valores predeterminados y se preparará para imprimirlos cuando se le llame …
#!/bin/sh _top_of_script_pr() ( IFS="$nl" ; set -f #only split at newlines and don"t expand paths printf %s\\n ${strings} ) 3<<-TEMPLATES ${nl= } ${PLACE:="your mother"s house"} ${EVENT:="the unspeakable."} ${ACTION:="heroin"} ${RESULT:="succeed."} ${strings:=" I went to ${PLACE} and saw ${EVENT} If you do ${ACTION} you will ${RESULT} "} #END TEMPLATES
MIDDLE
Aquí es donde define otras funciones para llamar a su función de impresión en función de sus resultados …
EVENT="Disney on Ice." _more_important_function() { #...some logic... [ $((1+one)) -ne 2 ] && ACTION="remedial mathematics" _top_of_script_pr } _less_important_function() { #...more logic... one=2 : "${ACTION:="calligraphy"}" _top_of_script_pr }
ABAJO
Ya lo tiene todo configurado, así que aquí es donde ejecutará y obtendrá los resultados.
_less_important_function : "${PLACE:="the cemetery"}" _more_important_function : "${RESULT:="regret it."}" _less_important_function
RESULTADOS
Voy a explicar por qué en un momento, pero ejecutar lo anterior produce los siguientes resultados:
_less_important_function()"s
primera ejecución:Fui a la casa de tu madre y vi Disney on Ice.
Si haces caligrafía tendrás éxito.
th es
_more_important_function():
Fui al cementerio y vi Disney on Ice.
Si haces matemáticas de recuperación tendrás éxito.
_less_important_function()
de nuevo:Fui al cementerio y vi Disney on Ice.
Si haces matemáticas de recuperación, te arrepentirás.
CÓMO FUNCIONA:
La característica clave aquí es el concepto de conditional ${parameter} expansion.
Puede establecer una variable en un valor solo si no está configurado o es nulo usando la forma:
${var_name
: =desired_value}
Si, en cambio, desea configurar solo una variable no configurada, debe omitir y los valores nulos permanecerían como están.
EN EL ALCANCE:
Puede notar que en el ejemplo anterior $PLACE
y $RESULT
se modifican cuando se configuran a través de parameter expansion
aunque _top_of_script_pr()
ya se ha llamado, presumiblemente configurándolos cuando se ejecuta. La razón por la que esto funciona es que _top_of_script_pr()
es una función ( subshelled )
– adjunto en parens
en lugar de { curly braces }
que se usa para los demás. Debido a que se llama en una subcapa, cada variable que establece es locally scoped
y cuando regresa a su capa principal esos valores desaparecen.
Pero cuando _more_important_function()
establece $ACTION
es globally scoped
por lo que afecta a _less_important_function()"s
segunda evaluación de $ACTION
porque _less_important_function()
establece $ACTION
solo a través de ${parameter:=expansion}.
Comentarios
- Es bueno ver que el valor predeterminado abreviado funciona en Bourne Shell
Respuesta
Experiencia personal.
A veces utilizo este formato en mis scripts para anular valores ad-hoc, p. ej.si tengo:
$ cat script.sh SOMETHING="${SOMETHING:-something}"; echo "$SOMETHING";
Puedo ejecutar:
$ env SOMETHING="something other than the default value" ./script.sh`
sin tener que cambiar el valor predeterminado original de SOMETHING
.
man bash
; busque el bloque » Expansión del parámetro » (aproximadamente al 28%). Estas asignaciones son, por ejemplo, funciones predeterminadas: » Use el valor predeterminado solo si aún no se ha establecido ninguno. »:-
establece el valor predeterminado, el:+
se usa para alterar el valor si la variable es no nulo. P.ej.v=option; cmd ${v:+ with $v}
Ejecutará » cmd con la opción «. Pero si $ v es nulo, solo ejecutará » cmd «.