Apenas atribua todas as variáveis e escreva a saída ao mesmo tempo.
f() { c= ; echo "${c:=$(date): $((a=3)) $((b=4))}" ; }
Agora, se você fizer:
f ; echo "$a $b $c"
Sua saída é:
Tue Jul 1 04:58:17 PDT 2014: 3 4
3 4 Tue Jul 1 04:58:17 PDT 2014: 3 4
Observe que este é um código portátil totalmente POSIX. Inicialmente, defino c=
a ''
cadeia nula porque a expansão do parâmetro limita a atribuição simultânea de variáveis + a avaliação a valores numéricos (como $((var=num))
) ou nulos ou inexistentes - ou, em outras palavras, você não pode configurar e avaliar simultaneamente uma variável em uma cadeia arbitrária se essa variável já tiver um valor atribuído. Portanto, apenas garanto que ele esteja vazio antes de tentar. Se eu não esvaziasse c
antes de tentar atribuí-lo, a expansão retornaria apenas o valor antigo.
Apenas para demonstrar:
sh -c '
c=oldval a=1
echo ${c:=newval} $((a=a+a))
'
###OUTPUT###
oldval 2
newval
não é atribuído ao $c
inline porque oldval
é expandido para ${word}
, enquanto a atribuição $((
aritmética inline sempre ocorre. Mas se não tem e está vazio ou não está definido ...=
))
$c
oldval
sh -c '
c=oldval a=1
echo ${c:=newval} $((a=a+a))
c= a=$((a+a))
echo ${c:=newval} $((a=a+a))
'
###OUTPUT###
oldval 2
newval 8
... então newval
é imediatamente atribuído e expandido para $c
.
Todas as outras maneiras de fazer isso envolvem alguma forma de avaliação secundária. Por exemplo, digamos que eu desejasse atribuir a saída de f()
a uma variável nomeada name
em um ponto e var
em outro. Como está escrito atualmente, isso não funcionará sem definir o var no escopo do chamador. Uma maneira diferente poderia ser assim:
f(){ fout_name= fout= set -- "${1##[0-9]*}" "${1%%*[![:alnum:]]*}"
(: ${2:?invalid or unspecified param - name set to fout}) || set --
export "${fout_name:=${1:-fout}}=${fout:=$(date): $((a=${a:-50}+1)) $((b=${b:-100}-4))}"
printf %s\\n "$fout"
}
f &&
printf %s\\n \
"$fout_name" \
"$fout" \
"$a" "$b"
Forneci um exemplo melhor formatado abaixo, mas chamado como acima, a saída é:
sh: line 2: 2: invalid or unspecified param - name set to fout
Wed Jul 2 02:27:07 PDT 2014: 51 96
fout
Wed Jul 2 02:27:07 PDT 2014: 51 96
51
96
Ou com diferentes $ENV
ou argumentos:
b=9 f myvar &&
printf %s\\n \
"$fout_name" \
"$fout" \
"$myvar" \
"$a" "$b"
###OUTPUT###
Tue Jul 1 19:56:42 PDT 2014: 52 5
myvar
Tue Jul 1 19:56:42 PDT 2014: 52 5
Tue Jul 1 19:56:42 PDT 2014: 52 5
52
5
Provavelmente, a coisa mais difícil de acertar quando se trata de avaliar duas vezes é garantir que as variáveis não quebrem aspas e executem códigos aleatórios. Quanto mais vezes uma variável é avaliada, mais difícil fica. A expansão de parâmetros ajuda bastante aqui, e usar export
ao contrário eval
é muito mais seguro.
No exemplo acima, f()
primeiro atribui $fout
a ''
cadeia nula e, em seguida, define parâmetros posicionais para testar nomes de variáveis válidos. Se ambos os testes não passarem, uma mensagem será emitida stderr
e o valor padrão de fout
será atribuído $fout_name
. Independentemente dos testes, no entanto, $fout_name
sempre é atribuído a um fout
ou ao nome que você especificar $fout
e, opcionalmente, seu nome especificado sempre recebe o valor de saída da função. Para demonstrar isso, escrevi este pequeno for
loop:
for v in var '' "wr;\' ong"
do sleep 10 &&
a=${a:+$((a*2))} f "$v" || break
echo "${v:-'' #null}"
printf '#\t"$%s" = '"'%s'\n" \
a "$a" b "$b" \
fout_name "$fout_name" \
fout "$fout" \
'(eval '\''echo "$'\''"$fout_name"\")' \
"$(eval 'echo "$'"$fout_name"\")"
done
Ele brinca com alguns com nomes de variáveis e expansões de parâmetros. Se tiver alguma questão, basta perguntar. Isso executa apenas as mesmas poucas linhas na função já representada aqui. Vale ressaltar, pelo menos, que as variáveis $a
e $b
se comportam de maneira diferente, dependendo se elas estão definidas na chamada ou já estão definidas. Ainda assim, for
ele quase não formata o conjunto de dados e é fornecido por f()
. Dar uma olhada:
###OUTPUT###
Wed Jul 2 02:50:17 PDT 2014: 51 96
var
# "$a" = '51'
# "$b" = '96'
# "$fout_name" = 'var'
# "$fout" = 'Wed Jul 2 02:50:17 PDT 2014: 51 96'
# "$(eval 'echo "$'"$fout_name"\")" = 'Wed Jul 2 02:50:17 PDT 2014: 51 96'
sh: line 2: 2: invalid or unspecified param - name set to fout
Wed Jul 2 02:50:27 PDT 2014: 103 92
'' #null
# "$a" = '103'
# "$b" = '92'
# "$fout_name" = 'fout'
# "$fout" = 'Wed Jul 2 02:50:27 PDT 2014: 103 92'
# "$(eval 'echo "$'"$fout_name"\")" = 'Wed Jul 2 02:50:27 PDT 2014: 103 92'
sh: line 2: 2: invalid or unspecified param - name set to fout
Wed Jul 2 02:50:37 PDT 2014: 207 88
wr;\' ong
# "$a" = '207'
# "$b" = '88'
# "$fout_name" = 'fout'
# "$fout" = 'Wed Jul 2 02:50:37 PDT 2014: 207 88'
# "$(eval 'echo "$'"$fout_name"\")" = 'Wed Jul 2 02:50:37 PDT 2014: 207 88'
$a
e$b
são variáveis locais em suaf
função. Você poderiaexport
, mas isso parece incompleto.