Historicamente, o shell Bourne e o Korn shell se comportou de maneira diferente. Como os dois lados de um pipe são executados em paralelo, em diferentes processos, não é possível que atribuições de variáveis em ambos os lados sejam preservadas no restante do script. Dado unset a; a=b | a=c
, a variável a
pode acabar não definida ou igual a b
ou igual a c
; não pode ser igual a ambos os b
e c
.
No shell Bourne, cada lado do operador de pipe é executado em um subshell (ou seja, em um processo de shell separado), portanto, as atribuições de variáveis não são preservadas. No shell Korn, o lado direito de um pipe é executado no processo shell original.
Como em muitos casos em que os comportamentos existentes diferem, o POSIX permite ambos os comportamentos. Conforme declarado na seção “Ambiente de Execução da Shell” :
each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment. All other commands will be executed in the current shell environment.
Some systems have implemented the last stage of a pipeline in the current environment so that commands such as:
command | read foo
set variable foo
in the current environment. This extension is allowed, but not required; therefore, a shell programmer should consider a pipeline to be in a subshell environment, but not depend on it.
Na prática, comandos diferentes do último sempre são executados em um subshell, exceto algumas otimizações onde o comportamento é o mesmo, a menos que você observe atentamente o número de processos que são criados. Ou seja, nenhum shell tem unset a; a=b | true; echo $a
print b
.
A maioria dos outros tipos de Bourne, como cinza, traço, bash, pdksh e mksh, se comportam como o shell Bourne. Zsh se comporta como o shell Korn. Versões recentes do bash podem mudar para o comportamento do ksh com shopt -s lastpipe
.