Basta atribuir todas as variáveis e escrever a saída ao mesmo tempo.
f() { c= ; echo "${c:=$(date): $((a=3)) $((b=4))}" ; }
Agora, se você fizer isso:
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 isso é totalmente código portátil POSIX. Inicialmente, defini c=
para a string ''
null porque a expansão do parâmetro limita a atribuição de variáveis simultâneas + avaliação a somente numéricos (como $((var=num))
) ou de valores nulos ou inexistentes - ou, em outros palavras, você não pode definir simultaneamente e avaliar uma variável para uma string arbitrária se essa variável já tiver um valor atribuído. Então eu só garanto que está vazio antes de tentar. Se eu não esvaziar c
antes de tentar atribuí-lo, a expansão só retornaria 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 a $c
em linha porque oldval
é expandido em ${word}
, enquanto a% em linha$((
aritmética =
designação ))
sempre ocorre. Mas se $c
não tiver oldval
e estiver vazio ou não estiver definido ...
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
é atribuído e expandido em $c
.
Todas as outras formas de fazer isso envolvem alguma forma de avaliação secundária. Por exemplo, digamos que eu quisesse atribuir a saída de f()
a uma variável chamada name
em um ponto e var
em outro. Como atualmente escrito, 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"
Eu forneci um exemplo formatado melhor 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 muito aqui e usar export
em oposição a eval
é muito mais seguro.
No exemplo acima, f()
primeiro atribui $fout
a ''
string nula e, em seguida, configura os parâmetros posicionais para testar os nomes de variáveis válidos. Se ambos os testes não forem transmitidos, será emitida uma mensagem para stderr
e o valor padrão de fout
será atribuído a $fout_name
. Independentemente dos testes, no entanto, $fout_name
é sempre atribuído a fout
ou o nome especificado e $fout
e, opcionalmente, o nome especificado sempre recebe o valor de saída da função.
Para demonstrar isso eu 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 toca em alguns com nomes de variáveis e expansões de parâmetros. Se tiver alguma questão, basta perguntar. Que somente executa as mesmas poucas linhas na função já representada aqui. Vale a pena mencionar, pelo menos, que as variáveis $a
e $b
se comportam de maneira diferente, dependendo de serem definidas na invocação ou definidas já. Ainda assim, o for
não faz quase nada, mas formata o conjunto de dados e é fornecido por f()
. Dê 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'