Tenho observado alguns scripts que outras pessoas escreveram (especificamente Red Hat), e muitas de suas variáveis são atribuídas usando a seguinte notação VARIABLE1="${VARIABLE1:-some_val}"
ou alguma outra expansão variáveis VARIABLE2="${VARIABLE2:-`echo $VARIABLE1`}"
Qual é o sentido de usar essa notação em vez de apenas declarar os valores diretamente (por exemplo, VARIABLE1=some_val
)?
Existem benefícios nesta notação ou possíveis erros que seriam evitados?
O :-
tem um significado específico neste contexto ?
Comentários
Resposta
Esta técnica permite que uma variável seja atribuída um valor se outra variável estiver vazia ou indefinida. OBSERVAÇÃO: Essa “outra variável” pode ser a mesma ou outra variável.
trecho
${parameter:-word} If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.
NOTA: Isso formulário também funciona, ${parameter-word}
. Se você gostaria de ver uma lista completa de todas as formas de expansão de parâmetro disponíveis no Bash, então sugiro que dê uma olhada neste tópico no wiki do Bash Hacker intitulado: “ Expansão de parâmetros “.
Exemplos
variável não” existe
$ echo "$VAR1" $ VAR1="${VAR1:-default value}" $ echo "$VAR1" default value
variável existe
$ VAR1="has value" $ echo "$VAR1" has value $ VAR1="${VAR1:-default value}" $ echo "$VAR1" has value
A mesma coisa pode ser feita avaliando outras variáveis ou executando comandos dentro da parte do valor padrão da notação.
$ VAR2="has another value" $ echo "$VAR2" has another value $ echo "$VAR1" $ $ VAR1="${VAR1:-$VAR2}" $ echo "$VAR1" has another value
Mais exemplos
Você também pode usar uma notação ligeiramente diferente onde “é apenas VARX=${VARX-<def. value>}
.
$ echo "${VAR1-0}" has another value $ echo "${VAR2-0}" has another value $ echo "${VAR3-0}" 0
No $VAR1
& já foram definidos com a string “tem outro valor”, mas $VAR3
foi indefinido, então o valor padrão foi usado, 0
.
Outro exemplo
$ VARX="${VAR3-0}" $ echo "$VARX" 0
Verificação e atribuição usando :=
notação
Por último, mencionarei o operador útil, :=
. Isso fará uma verificação e atribuirá um valor se a variável em teste estiver vazia ou indefinida.
Exemplo
Observe que $VAR1
é agora definir. O operador :=
fez o teste e a atribuição em uma única operação.
$ unset VAR1 $ echo "$VAR1" $ echo "${VAR1:=default}" default $ echo "$VAR1" default
No entanto, se o valor for definido antes, então é deixado sozinho.
$ VAR1="some value" $ echo "${VAR1:=default}" some value $ echo "$VAR1" some value
Tabela de referência dândi útil
Referências
- Expansões de parâmetros – Wiki Bash Hackers
- 10.2. Substituição de parâmetro
- Expansões de parâmetros Bash
Comentários
- Observe que nem todas essas expansões estão documentadas em
bash
. O${var:-word}
no Q é, mas não o${var-word}
acima. O POSIX documentação tem uma boa tabela, porém, pode valer a pena copiá-la para o é a resposta – pubs.opengroup.org/onlinepubs/9699919799/utilities/… - @ Graeme, está documentado, você só precisa prestar atenção a Omitindo os resultados de dois pontos em um teste apenas para um parâmetro que não está definido.
- Usando
echo "${FOO:=default}"
é ótimo se você realmente deseja oecho
. Mas se você não ‘ t, tente o:
integrado …: ${FOO:=default}
Seu$FOO
está definido paradefault
como acima (ou seja, se ainda não estiver definido). Mas não ‘ s nenhum eco de$FOO
no processo. - Ok, encontrei uma resposta: stackoverflow.com / q / 24405606/1172302 . Usar o
${4:-$VAR}
funcionará. - +1 apenas para a resposta detalhada. Mas também pelo fato de você fazer referência ao excelente bash wiki. E também pelo fato de você dar exemplos e uma tabela. Inferno, apenas + 1s até o final 🙂 Quanto a mim, quase acertei a sintaxe, mas não muito – eu simplesmente não ‘ me importei o suficiente para pesquisar a página de manual (não é difícil mas eu não conseguia ‘ não lembrar em que título estava e ‘ estive acordado desde as 4 da manhã :() ..
Resposta
@slm já incluiu os documentos POSIX – que são muito úteis – mas não expandem realmente como esses parâmetros podem ser combinados para afetar um ao outro. Ainda não há qualquer menção aqui a este formulário:
${var?if unset parent shell dies and this message is output to stderr}
Este é um trecho de outra resposta minha , e acho que demonstra muito bem como funcionam:
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?
Outro exemplo de mesmo :
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
O exemplo acima tira vantagem de todas as 4 formas de substituição de parâmetro POSIX e seus diversos testes :colon null
ou not null
. Há mais informações no link acima e aqui está novamente .
Outra coisa que as pessoas geralmente não consideram sobre ${parameter:+expansion}
é o quão útil pode ser em um documento aqui. Aqui está outro trecho de um resposta diferente :
TOP
Aqui, você definirá alguns padrões e se preparará para imprimi-los quando chamado …
#!/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
MEIO
Aqui é onde você define outras funções para chamar sua função de impressão com base em seus 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 }
BOTTOM
Você já configurou tudo agora, então aqui “é onde você” executará e obterá seus resultados.
_less_important_function : "${PLACE:="the cemetery"}" _more_important_function : "${RESULT:="regret it."}" _less_important_function
RESULTADOS
Explicarei o porquê em um momento, mas a execução do procedimento acima produz os seguintes resultados:
_less_important_function()"s
primeira execução:Fui à casa da sua mãe e vi Disney on Ice.
Se você fizer caligrafia , terá sucesso.
th en
_more_important_function():
Fui ao cemitério e viu Disney no gelo.
Se você fizer matemática corretiva , terá sucesso.
_less_important_function()
novamente:Fui ao cemitério e vi Disney no gelo.
Se você fizer matemática corretiva, você se arrependerá.
COMO FUNCIONA:
O principal recurso aqui é o conceito de conditional ${parameter} expansion.
Você pode definir uma variável para um valor apenas se não estiver definido ou nulo usando o formulário:
${var_name
: =desired_value}
Se, em vez disso, você quiser definir apenas uma variável não definida, omita o e os valores nulos permaneceriam como estão.
NO ESCOPO:
Você pode notar que no exemplo acima $PLACE
e $RESULT
são alterados quando configurados via parameter expansion
embora _top_of_script_pr()
já tenha sido chamado, presumivelmente configurando-os quando for executado. A razão de isso funcionar é que _top_of_script_pr()
é uma função ( subshelled )
– incluí em parens
em vez de { curly braces }
usado para os outros. Por ser chamado em um subshell, cada variável que define é locally scoped
e, conforme retorna ao shell pai, esses valores desaparecem.
Mas quando _more_important_function()
define $ACTION
, é globally scoped
para que afete _less_important_function()"s
segunda avaliação de $ACTION
porque _less_important_function()
define $ACTION
somente por meio de ${parameter:=expansion}.
Comentários
- É bom ver que o valor padrão abreviado funciona no Bourne Shell
Resposta
Experiência pessoal.
Eu uso esse formato às vezes em meus scripts para fazer a substituição ad hoc de valores, por exemplo,se eu tenho:
$ cat script.sh SOMETHING="${SOMETHING:-something}"; echo "$SOMETHING";
Posso executar:
$ env SOMETHING="something other than the default value" ./script.sh`
sem ter que mudar o valor padrão original de SOMETHING
.
man bash
; procure o bloco ” Expansão de parâmetro ” (em cerca de 28%). Essas atribuições são, por exemplo, funções padrão: ” Use o valor padrão apenas se nenhum tiver sido definido ainda. ”:-
define o valor padrão, o:+
é usado para alterar o valor se a variável for não nulo. Por exemplo.v=option; cmd ${v:+ with $v}
Será executado ” cmd com a opção “. Mas se $ v for nulo, ele executará apenas ” cmd “.