Eu estava querendo inicializar algumas strings na parte superior do meu script com variáveis que ainda não foram definidas, como:
str1='I went to ${PLACE} and saw ${EVENT}'
str2='If you do ${ACTION} you will ${RESULT}'
e, em seguida, mais tarde PLACE
, EVENT
, ACTION
, e RESULT
será definido. Quero poder imprimir minhas strings com as variáveis expandidas. É minha única opção eval
? Isso parece funcionar:
eval "echo ${str1}"
isso é padrão? Existe uma maneira melhor de fazer isso? Seria bom não executar, eval
considerando que as variáveis podem ser qualquer coisa.
Pelo que entendi, não acredito que nenhuma dessas respostas esteja correta.
eval
não é necessário de forma alguma, nem você precisa avaliar duas vezes suas variáveis.É verdade que o @Gilles chega muito perto, mas ele não aborda o problema de possivelmente substituir valores e como eles devem ser usados se você precisar deles mais de uma vez. Afinal, um modelo deve ser usado mais de uma vez, certo?
Eu acho que é mais a ordem na qual você os avalia que é importante. Considere o seguinte:
TOPO
Aqui você definirá alguns padrões e se preparará para imprimi-los quando chamados ...
MEIO
É aqui que você define outras funções para chamar sua função de impressão com base em seus resultados ...
INFERIOR
Agora você tem tudo configurado, então aqui é onde você executa e obtém seus resultados.
RESULTADOS
Falarei sobre o motivo daqui a pouco, mas a execução do procedimento acima produz os seguintes resultados:
COMO FUNCIONA:
O principal recurso aqui é o conceito de
conditional ${parameter} expansion.
Você pode definir uma variável para um valor somente se estiver desconfigurada ou nula usando o formulário:Se, em vez disso, você desejar definir apenas uma variável não configurada, você omitirá os
:colon
valores nulos e permanecerá como está.NO ÂMBITO DE APLICAÇÃO:
Você pode perceber isso no exemplo acima
$PLACE
e$RESULT
ser alterado quando definido viaparameter expansion
mesmo que_top_of_script_pr()
já tenha sido chamado, presumivelmente configurando-os quando é executado. A razão pela qual isso funciona é que_top_of_script_pr()
é uma( subshelled )
função - eu a incluí emparens
vez da{ curly braces }
usada para as outras. Como é chamado em um subshell, todas as variáveis que ele define sãolocally scoped
e, quando retornam ao shell pai, esses valores desaparecem.Mas quando
_more_important_function()
conjuntos$ACTION
,globally scoped
isso afeta a_less_important_function()'s
segunda avaliação,$ACTION
porque_less_important_function()
conjuntos$ACTION
somente via${parameter:=expansion}.
:NULO
E por que eu uso o líder
:colon?
Bem, aman
página dirá a você que: does nothing, gracefully.
você vê,parameter expansion
é exatamente o que parece -expands
ao valor do${parameter}.
Então, quando definimos uma variável,${parameter:=expansion}
ficamos com seu valor - que o shell exibirá tente executar em linha. Se tentasse executarthe cemetery
, cuspiria alguns erros em você.PLACE="${PLACE:="the cemetery"}"
produziria os mesmos resultados, mas também é redundante neste caso e eu preferi que o shell: ${did:=nothing, gracefully}.
Ele permite que você faça isso:
AQUI-DOCUMENTOS
A propósito, a definição em linha de uma variável nula ou não definida também é o motivo pelo qual o seguinte funciona:
A melhor maneira de pensar em a
here-document
é como um arquivo real transmitido para um descritor de arquivo de entrada. É mais ou menos isso, mas conchas diferentes as implementam de maneira um pouco diferente.De qualquer forma, se você não citar o
<<LIMITER
texto, ele será transmitido e avaliado comoexpansion.
So declarar uma variável em umhere-document
pode funcionar, mas apenas através doexpansion
qual você limita a definir apenas variáveis que ainda não estão definidas. Ainda assim, isso se adapta perfeitamente às suas necessidades conforme você as descreveu, pois seus valores padrão sempre serão definidos quando você chama sua função de impressão de modelo.POR QUE NÃO
eval?
Bem, o exemplo que apresentei fornece um meio seguro e eficaz de aceitar.
parameters.
Como ele lida com o escopo, todas as variáveis dentro do conjunto via${parameter:=expansion}
são definíveis de fora. Portanto, se você colocar tudo isso em um script chamado template_pr.sh e executar:Você obteria:
Isso não funcionaria para as variáveis que foram literalmente definidas no script, como
$EVENT, $ACTION,
e,$one,
mas eu apenas as defini dessa maneira para demonstrar a diferença.Em qualquer caso, a aceitação de informações desconhecidas em uma
evaled
instrução é inerentemente insegura, enquantoparameter expansion
foi especificamente projetada para isso.fonte
Você pode usar espaços reservados para modelos de string em vez de variáveis não expandidas. Isso ficará confuso rapidamente. Se o que você está fazendo é muito pesado para modelos, considere um idioma com uma biblioteca de modelos real.
A desvantagem do acima é que a variável do modelo deve ser sua própria palavra (por exemplo, você não pode fazer
"%prefix%foo"
). Isso pode ser corrigido com algumas modificações ou simplesmente codificando a variável do modelo em vez de ser dinâmica.fonte