Você perceberá que em bash
/ ksh
echo foo | echo "$(cat)"
exibe foo
, mas
<<< foo echo "$(cat)"
Não.
No primeiro caso, o $(cat)
é expandido no processo filho que executará echo
depois que seu stdin for redirecionado do canal.
No segundo caso, o $(cat)
é expandido antes do redirecionamento.
pipes e redirecionamentos são coisas diferentes. pipes envolvem algum redirecionamento , mas também iniciam comandos em paralelo. Isso acontece cedo, antes dos redirecionamentos dentro de cada componente do pipe.
Em zsh
$ sleep 1 | ps -jfH $(ps -fH >&2)
UID PID PPID C STIME TTY TIME CMD
chazelas 2495 2494 0 20:59 pts/1 00:00:00 /bin/zsh
chazelas 31201 2495 0 21:20 pts/1 00:00:00 sleep 1
chazelas 31202 2495 0 21:20 pts/1 00:00:00 ps -fH
UID PID PPID PGID SID C STIME TTY TIME CMD
chazelas 2495 2494 2495 2495 0 20:59 pts/1 00:00:00 /bin/zsh
chazelas 31201 2495 31201 2495 0 21:20 pts/1 00:00:00 sleep 1
chazelas 31203 2495 31201 2495 0 21:20 pts/1 00:00:00 ps -jfH
Você notará que, desta vez, a substituição do comando é expandida pelo shell pai.
Uma coisa a ter em mente é que, em zsh
, os pipes são tratados um pouco mais como redirecionamentos em particular quando se trata da opção mult_ios
(ativada por padrão).
Quando você faz:
echo foo > file | tr o e
foo
vai para os dois file
e tr
.
Em:
uname | cat < /etc/issue
cat
é alimentado com a saída de uname
e o conteúdo de /etc/issue
. Portanto, em zsh
, o redirecionamento de <
/ >
e do pipe deve acontecer no mesmo estágio. De preferência após as expansões.
Em qualquer caso, você sempre pode fazer:
echo foo | { echo "$(cat)"; }
em zsh
e bash
/ ksh
, como sempre é possível fazer:
{ echo "$(cat)"; } <<< foo
em bash
e zsh
.
Quanto à causa do:
tail: error reading 'standard input': Input/output error
erro. Em shells interativos, uma vez que a substituição de comandos é feita no pai, isso não é feito no grupo de processos em primeiro plano do terminal.
tail
será executado no grupo de processos do shell pai. Se esse shell for o líder da sessão, ele será um grupo de processos órfãos , portanto quando tail
tentar ler o dispositivo tty, ele falhará com a EIO.
Se zsh
não foi o líder da sessão. Por exemplo, se você iniciou zsh
de outro shell, o grupo de processos receberia um SIGTTIN. O processo principal do shell iria ignorá-lo, mas tail
acabaria sendo suspenso.