Ok, vamos quebrar isso. Um subshell executa seu conteúdo em uma cadeia (isto é, agrupa-os). Isso realmente faz sentido intuitivo como um subshell é criado simplesmente cercando a cadeia de comandos com ()
. Mas, além do conteúdo do subshell ser agrupado em execução, você ainda pode usar um subshell como se fosse um único comando. Ou seja, um subshell ainda tem um stdin
, stdout
e stderr
, então você pode canalizar coisas de e para um subshell.
Por outro lado, a substituição de comando não é a mesma coisa que simplesmente encadear comandos juntos. Em vez disso, a substituição de comando serve para atuar um pouco como um acesso variável, mas com uma chamada de função. As variáveis, ao contrário dos comandos, não possuem os descritores de arquivos padrão, portanto você não pode canalizar nada para ou de uma variável (geralmente falando), e o mesmo vale para as substituições de comandos.
Para tentar deixar isso mais claro, o que segue é um conjunto de exemplos talvez pouco claros (mas precisos) e um conjunto de, o que eu acho que pode ser, exemplos mais fáceis de entender.
Digamos que o comando date -u
forneça o seguinte:
Thu Jul 2 13:42:27 UTC 2015
Mas, queremos manipular a saída deste comando. Então, vamos canalizá-lo para algo como sed
:
$ date -u | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
Uau, isso foi divertido! O seguinte é completamente equivalente ao acima (exceto algumas diferenças de ambiente que você pode ler nas páginas man sobre seu shell):
$ (date -u) | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
Isso não deve ser surpresa, já que tudo que fizemos foi o grupo date -u
. No entanto, se fizermos o seguinte, obteremos algo que pode parecer um pouco estranho no início:
$ $(date -u) | sed -e 's/ / /g'
command not found: Thu
Isso ocorre porque $(date -u)
equivale a digitar exatamente o que date -u
gera. Então, o acima é equivalente ao seguinte:
$ Thu Jul 2 13:42:27 UTC 2015 | sed -e 's/ / /g'
O que, naturalmente, irá cometer erros porque Thu
não é um comando (pelo menos não um que eu saiba); e certamente não canaliza nada para stdout
(então sed
nunca receberá nenhuma entrada).
Mas, como sabemos que as substituições de comandos funcionam como variáveis, podemos corrigir esse problema facilmente porque sabemos como canalizar o valor de uma variável para outro comando:
$ echo $(date -u) | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
Mas, como qualquer variável no bash , você provavelmente deve citar as substituições de comandos com ""
.
Agora, para o exemplo talvez mais simples; considere o seguinte:
$ pwd
/home/hypothetical
$ echo pwd
pwd
$ echo "$(pwd)"
/home/hypothetical
$ echo "$HOME"
/home/hypothetical
$ echo (pwd)
error: your shell will tell you something weird that roughly means “Whoa! you tried to have me echo something that isn't text!”
$ (pwd)
/home/hypothetical
Não sei como descrevê-lo mais simples que isso. A substituição de comandos funciona como um acesso variável, onde o subshell ainda funciona como um comando.