De acordo com isso e isso , um subshell é iniciado usando parênteses (…)
.
( echo "Hello" )
De acordo com isto , isto e isto , um processo é bifurcado quando o comando é iniciado com um&
echo "Hello" &
A especificação Posix usa a palavra subshell
nesta página, mas não a define e, também, na mesma página, não define "processo filho" .
Ambos estão usando a fork()
função kernel , correto?
Qual é a diferença exata então chamar alguns garfos de "subcasca" e outros garfos de "processo filho".
child process
poderia ter um ambiente distinto do quemain
: Como em( LANG=C eval 'echo "$LANG"' )
. Esse processo filho (entre parênteses) também é um subshell (ambiente diferente)?( )
é, por definição, um subshell com seu próprio ambiente de execução. Meu argumento é que não é necessário que um subshell seja implementado como um processo filho (como Stéphane aponta em sua resposta com o exemplo ksh93). Parece que o subshell e o processo filho não precisam ser os dois resultados de umafork()
chamada; portanto, procurar a diferença entre dois tipos de garfo não parece o ponto de vista certo para mim. Por isso estava tentando entender melhor sua pergunta.Respostas:
Na terminologia POSIX, um ambiente de subcasca está vinculado à noção de Shell Execution Environment .
Um ambiente de subshell é um ambiente de execução de shell separado, criado como uma duplicata do ambiente pai. Esse ambiente de execução inclui coisas como arquivos abertos, umask, diretório de trabalho, variáveis / funções / aliases do shell ...
As alterações nesse ambiente de subcasca não afetam o ambiente pai.
Tradicionalmente no shell Bourne ou no ksh88 no qual a especificação POSIX se baseia, isso era feito bifurcando um processo filho.
As áreas em que o POSIX requer ou permite a execução de comandos em um ambiente de subcamadas são aquelas em que o ksh88 tradicionalmente bifurcava um processo de shell filho.
No entanto, não força as implementações a usar um processo filho para isso.
Um shell pode optar por implementar esse ambiente de execução separado da maneira que desejar.
Por exemplo, o ksh93 faz isso salvando os atributos do ambiente de execução pai e restaurando-os após o término do ambiente do subshell em contextos onde a bifurcação pode ser evitada (uma otimização da bifurcação é bastante cara na maioria dos sistemas).
Por exemplo, em:
O POSIX exige
cd /foo
que seja executado em um ambiente separado e que produza algo como:Não requer que ele seja executado em um processo separado. Por exemplo, se stdout se tornar um pipe quebrado, a
pwd
execução no ambiente de subshell pode muito bem ter o SIGPIPE enviado para o primeiro e único processo de shell.A maioria dos shells, inclusive
bash
, o implementará avaliando o código interno(...)
em um processo filho (enquanto o processo pai aguarda sua finalização), mas o ksh93 fará isso ao executar o código interno(...)
, tudo no mesmo processo:cd
seguida, salve o diretório de trabalho anterior (geralmente em um descritor de arquivo aberto com O_CLOEXEC), salve o valor das variáveis OLDPWD, PWD e qualquer coisa quecd
possa modificar e faça ochdir("/bar")
fchdir()
no fd salvo) e tudo o mais que o subshell pode ter modificado.Existem contextos em que um processo filho não pode ser evitado. O ksh93 não entra em:
var=$(subshell)
(subshell)
Mas faz em
{ subshell; } &
{ subshell; } | other command
Ou seja, os casos em que as coisas precisam ser executadas em processos separados para que possam ser executadas simultaneamente.
As otimizações do ksh93 vão além disso. Por exemplo, enquanto em
a maioria dos shells faria bifurcar um processo, fazer o filho executar o
pwd
comando com seu stdout redirecionado para um canal,pwd
gravar o diretório de trabalho atual nesse canal e o processo pai ler o resultado na outra extremidade do canal,ksh93
virtualizando tudo isso exigindo o garfo nem o tubo. Um garfo e tubo só seriam usados para comandos não integrados.Observe que existem outros contextos que subshells para os quais shells bifurcam um processo filho. Por exemplo, para executar um comando que é armazenado em um executável separado (e que não é um script destinado ao mesmo interpretador de shell), um shell teria que bifurcar um processo para executar esse comando nele, caso contrário, não seria capaz de executar mais comandos depois que esse comando retornar.
Dentro:
Isso não é um subshell, o comando será avaliado no atual ambiente de execução do shell, a
n
variável do atual ambiente de execução do shell será incrementada, mas o shell bifurcará um processo filho para executar esse/bin/echo
comando nele com a expansão de$((n += 1))
como argumento .Muitos shells implementam uma otimização na medida em que não bifurcam um processo filho para executar esse comando externo, se for o último comando de um script ou um subshell (para os subshells implementados como processos filhos). (
bash
no entanto, somente o faz se esse comando for o único comando do subshell).O que isso significa é que, com esses shells, se o último comando no subshell for um comando externo, o subshell não fará com que um processo extra seja gerado. Se você comparar:
com
haverá o mesmo número de processos criados; somente no segundo caso, o segundo fork será feito anteriormente, para que
a=2
seja executado em um ambiente de subshell.fonte
Subshell
O shell filho também é chamado de subshell. O subshell pode ser criado a partir do shell pai e de outro shell. O subshell pode ser criado usando:
1. Lista de processos
Uma lista de processos é um agrupamento de comandos entre parênteses. Exemplo:
Isso imprimirá o diretório de trabalho atual e o número de shell gerado. OBSERVAÇÃO A chamada do subshell é cara.
2. Coprocesso
Ele gera um subshell no modo de segundo plano e executa um comando dentro desse subshell.
Se você digitar
jobs
comandovocê verá o sono como processo em segundo plano sendo executado em segundo plano.
Bifurcando um processo filho
Um processo filho em computação é um processo criado por outro processo. Sempre que um comando externo é executado, um processo filho é criado. Esta ação é denominada bifurcação.
Assim
ps -f
como o comando externo (isto é, um comando externo, às vezes chamado de comando do sistema de arquivos, é um programa que existe fora do shell bash.) Isso criará um processo filho com o ID pai do shell bash a partir do qual é executado.fonte
Ambos (subshell e shell filho) são um processo separado do shell pai (ambos são filhos do shell pai). Ou seja, eles têm PIDs diferentes. E ambos começam com um garfo (cópia) do shell pai.
Um subshell é uma cópia do shell pai, na qual variáveis, funções, sinalizadores e tudo estão disponíveis como estavam no shell pai. Modificações de tais valores não afetam o pai.
Um shell filho inicia como um fork, mas é redefinido para os valores padrão do shell fornecidos pelas configurações de início. Torna-se um processo usado para executar algum código (um shell ou um comando).
Um subshell pode acessar valores variáveis:
Um shell filho não pôde (variáveis não exportadas):
fonte