Use a substituição de comandos:
myvar='echo foo'
ou
myvar=$(echo foo)
Estou tentando obter a saída de um pipe em uma variável. Eu tentei as seguintes coisas:
echo foo | myvar=$(</dev/stdin)
echo foo | myvar=$(cat)
echo foo | myvar=$(tee)
Mas $myvar
está vazio.
Eu não quero fazer:
myvar=$(echo foo)
Porque eu não quero gerar uma subcamada.
Alguma idéia?
Editar: não quero gerar um subshell porque o comando antes do pipe precisa editar as variáveis globais, o que não é possível em uma subshell. Pode? A coisa echo
é apenas para simplificação. É mais como:
complex_function | myvar=$(</dev/stdin)
E eu não entendo, por que isso não funciona. Isso funciona por exemplo:
complex_function | echo $(</dev/stdin)
Use a substituição de comandos:
myvar='echo foo'
ou
myvar=$(echo foo)
Em ksh93
, você pode usar:
var=${
my command that updates global variable
}
Essa é uma forma de substituição de comando que não gera uma subcamada. Para comandos que são comandos internos, em vez de fazer com que eles gravem seus resultados em um canal (para o qual você precisaria de diferentes processos para ler e escrever no pipe para evitar bloqueios), ksh93
apenas faz com que eles não produzam nada, mas reunir o que eles estariam produzindo para fazer a expansão.
$ ksh -c 'a=${ b=123; echo foo;}; echo "$a $b"'
foo 123
A substituição de comandos do fish
também se comporta assim:
$ fish -c 'set a (set b 123; echo foo); echo $a $b'
foo 123
Na maioria dos outros shells, você usaria um arquivo temporário:
my command that updates global variable > file
var=$(cat file) # can be optimised to $(<file) with some shells
No Linux, e com bash
ou zsh
(que usam arquivos temporários para <<<
), você pode fazer:
{ my command that updates global variable > /dev/fd/3 &&
var=$(cat<&3); } 3<<< ''
A solução correta é usar a substituição de comando assim:
variable=$(complex_command)
como em
message=$(echo 'hello')
Seu pipeline:
echo 'hello' | message=$(</dev/stdin)
ou
echo 'hello' | read message
realmente funciona. O único problema é que o shell que você está usando executará a segunda parte do pipeline em um subshell. Este subshell é destruído quando o pipeline sai, então o valor de $message
não é retido no shell.
Aqui você pode ver que funciona:
$ echo 'hello' | { read message; echo "$message" }
hello
... mas como o ambiente do subshell é separado (e desaparecido):
$ echo "$message"
(sem saída)
Uma solução para você seria mudar para ksh93
, que é mais inteligente sobre isso:
$ echo 'hello' | read message
$ echo "$message"
hello
Outra solução para bash
seria definir a opção lastpipe
shell. Isso faria com que a última parte do pipeline fosse executada no ambiente atual. No entanto, isso não funciona em shells interativos, pois lastpipe
exige que o controle de trabalho não esteja ativo.
#!/bin/bash
shopt -s lastpipe
echo 'hello' | read message
echo "$message"