in bash or zsh, I can use following syntax to read from pipe into variables.
echo AAA BBB | read X Y ; echo $X
Não, você não pode. Não no Bash com as configurações padrão.
$ ./bash5.0-alpha -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X=\"$X\""'
Bash=5.0.0(1)-alpha X=""
$ bash -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X=\"$X\""'
Bash=4.4.12(1)-release X=""
O Bash executa todos os comandos em um pipeline em ambientes subshell separados, portanto, as alterações nas variáveis do shell não são visíveis fora do pipeline. Dash é semelhante aqui.
Zsh e ksh (implementações AT & T, não pdksh
ou derivadas) executam o último comando do pipeline no ambiente principal do shell, então funciona:
$ zsh -c 'echo AAA BBB | read X Y ; echo "Zsh=$ZSH_VERSION X=\"$X\""'
Zsh=5.3.1 X="AAA"
No Bash, você pode usar shopt -s lastpipe
para fazer o que o ksh e o zsh fazem (só funciona em shells não-interativos):
$ bash -O lastpipe -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X=\"$X\""'
Bash=4.4.12(1)-release X="AAA"
Mas não acho que exista essa opção para o Dash.
No Bash você também pode usar a substituição de processos ao invés do pipe, mas isso não é uma opção no Dash.
As soluções alternativas girariam em torno de tornar o lado direito do loop uma instrução composta ou uma função e, assim, usar o valor lido do canal no mesmo ambiente em que foi lido.
$ dash -c 'echo AAA BBB | { read X Y ; echo "X=\"$X\""; } '
X="AAA"
$ dash -c 'f() { read X Y ; echo "X=\"$X\""; }; echo AAA BBB | f'
X="AAA"
Ou use um documento aqui:
read X Y << EOF
$(echo AAA BBB)
EOF