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 ...
#!/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 que 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
}
INFERIOR
Agora você tem tudo configurado, então aqui é onde você executa e obtém seus resultados.
_less_important_function
: "${PLACE:="the cemetery"}"
_more_important_function
: "${RESULT:="regret it."}"
_less_important_function
RESULTADOS
Falarei sobre o motivo daqui a pouco, mas a execução do procedimento acima produz os seguintes resultados:
_less_important_function()'s
Primeira corrida:
Fui à casa de sua mãe e vi Disney on Ice.
Se você fizer caligrafia, terá sucesso.
então _more_important_function():
Fui ao cemitério e vi Disney on Ice.
Se você praticar matemática corretiva, terá sucesso.
_less_important_function()
novamente:
Fui ao cemitério e vi Disney on Ice.
Se você pratica matemática corretiva, vai se arrepender.
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:
${var_name
: =desired_value}
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 via parameter 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í em parens
vez da { curly braces }
usada para as outras. Como é chamado em um subshell, todas as variáveis que ele define são locally 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, a man
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 executar the 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:
echo ${var:=something or other}
echo $var
something or other
something or other
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:
<<HEREDOC echo $yo
${yo=yoyo}
HEREDOC
yoyo
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 como expansion.
So declarar uma variável em um here-document
pode funcionar, mas apenas através do expansion
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:
% RESULT=something_else template_pr.sh
Você obteria:
Fui à casa de sua mãe e vi Disney on Ice
Se você fizer caligrafia, irá
Eu fui ao cemitério e vi Disney on Ice
Se você pratica matemática corretiva, irá
Eu fui ao cemitério e vi Disney on Ice
Se você pratica matemática corretiva, irá
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, enquanto parameter expansion
foi especificamente projetada para isso.