A questão central é como os operadores &&
e |
conectam os dois comandos.
O &&
conecta os comandos pelo código de saída.
O |
conecta os dois comandos através dos descritores de arquivos (stdin, stdout).
Vamos simplificar primeiro. Podemos remover a tarefa e escrever:
echo $(cd ~ && pwd)
echo $(cd ~ | pwd)
Podemos até mesmo remover o sub-shell de execução de comandos para analisar isso:
$ cd ~ && pwd
$ cd ~ | pwd
& &
Se alterarmos o prompt para mostrar o diretório onde os comandos são executados, algo como PS1='\w\$ '
, veremos isto:
/tmp/user$ cd ~ && pwd
/home/user
~$
- O comando
cd ~
alterou o "diretório atual" para a home do usuário real que está executando o comando ( /home/user
).
- Como o resultado do comando foi bem-sucedido (código de saída 0), o próximo comando após o & & é executado
- E o "diretório de trabalho atual" é impresso.
- O shell em execução alterou seu
pwd
para ~
, conforme mostrado no prompt de ~$
.
Se a mudança de diretório foi mal sucedida (código de saída não 0) por algum motivo (diretório não existe, bloco de permissões lendo o diretório) o próximo comando não será executado.
Exemplo:
/tmp/user$ false && pwd
/tmp/user$ _
O código de saída 1 de false
impede a execução do próximo comando.
Assim, o código de saída do "comando 1" é o que afeta o "comando 2".
Agora, os efeitos de todo o comando:
/tmp/user$ echo $(cd ~ && pwd)
/home/user
/tmp/user$ _
O diretório foi alterado, mas dentro de um sub-shell $(…)
, o diretório alterado é impresso em /home/user
, mas é imediatamente descartado quando o sub-shell é fechado. O pwd volta a ser o diretório inicial ( /tmp/user
).
|
Isso é o que acontece:
/tmp/user$ cd ~ | pwd
/tmp/user
/tmp/user$ _
O meta-caractere |
(não um verdadeiro operador) sinaliza ao shell para criar o que é chamado de "Pipe", (no bash) cada comando em cada lado do pipe ( |
) é definido dentro de cada próprio sub-shell, primeiro o comando do lado direito e, em seguida, o da esquerda. O descritor do arquivo de entrada ( /dev/stdin
) do comando à direita está conectado ao descritor de saída ( /dev/stdout
) e, em seguida, ambos os comandos são iniciados e deixados para interagir. O comando esquerdo ( cd -
) não tem saída e, também, o comando correto ( pwd
) não aceita entrada. Então, cada um é executado independentemente dentro de cada sub-shell.
- O
cd ~
altera o pwd de um shell.
- O
pwd
imprime o pwd (completamente independente) do outro sub-shell.
As alterações em cada shell são descartadas quando o pipe termina, o sub-shell externo não alterou o pwd.
É por isso que os dois comandos são conectados apenas por "descritores de arquivo".
Neste caso, não há nada enviado e nada é lido.
O comando inteiro:
$ echo "$(cd ~ | pwd)"
Apenas imprimirá o diretório onde o comando foi executado.