Qual é a diferença exata entre um “subshell” e um “processo filho”?

7

De acordo com este e isto , um subshell é iniciado usando parêntese (…) .

( echo "Hello" )

De acordo com este , 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 define e, também, na mesma página, não define "processo filho" .

Ambos estão usando a função fork() do kernel, correto?

Qual é a diferença exata para chamar alguns forks de "sub-shell" e alguns outros forks de "processo filho".

    
por Isaac 31.01.2018 / 18:12

2 respostas

10

Na terminologia POSIX, um ambiente subshell está vinculado à noção de Ambiente de Execução da Shell .

Um ambiente 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 de shell ...

As alterações nesse ambiente de subshell não afetam o ambiente pai.

Tradicionalmente, no shell Bourne ou no ksh88, no qual a especificação POSIX é baseada, isso foi feito ao bifurcar um processo filho.

As áreas onde o POSIX requer ou permite que o comando seja executado em um ambiente de subshell são aquelas em que tradicionalmente o ksh88 bifurcava um processo de shell filho.

No entanto, isso 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 quiser.

Por exemplo, o ksh93 faz isso salvando os atributos do ambiente de execução pai e restaurando-os na finalização do ambiente subshell em contextos nos quais o forking pode ser evitado (como uma otimização, o forking é muito caro na maioria dos sistemas). p>

Por exemplo, em:

cd /foo; pwd
(cd /bar; pwd)
pwd

O POSIX requer que o cd /foo seja executado em um ambiente separado e que produza algo como:

/foo
/bar
/foo

Não é necessário que ele seja executado em um processo separado. Por exemplo, se o stdout se tornar um cano quebrado, pwd executado no ambiente subshell poderia muito bem ter o SIGPIPE enviado para o único processo de shell.

A maioria dos shells incluindo bash irão implementá-lo avaliando o código dentro de (...) em um processo filho (enquanto o processo pai aguarda sua finalização), mas o ksh93 irá executar o código dentro de (...) , all in o mesmo processo:

  • lembre-se que está em um ambiente subshell.
  • após cd , 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 que cd possa modificar e, em seguida, faça o chdir("/bar")
  • Ao retornar do subshell, o diretório de trabalho atual é restaurado (com fchdir() no fd salvo) e tudo o mais que a subshell pode ter modificado.

Existem contextos em que um processo filho não pode ser evitado. O ksh93 não entra em garfo:

  • var=$(subshell)
  • (subshell)

Mas em

  • { subshell; } &
  • { subshell; } | other command

Ou seja, os casos em que as coisas precisam ser executadas em processos separados para que possam ser executados simultaneamente.

As otimizações do ksh93 vão além disso. Por exemplo, enquanto em

var=$(pwd)

a maioria das shells processaria um processo, faça o filho executar o comando pwd com seu stdout redirecionado para um pipe, pwd escreva o diretório de trabalho atual para esse canal e o processo pai leia o resultado na outra extremidade do tubo, ksh93 virtualiza tudo isso sem exigir o garfo nem o tubo. Um fork e pipe seriam usados apenas para comandos não incorporados.

Note que existem contextos que não são subchaves para os quais os shells forjam 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 o comando retornar.

Em:

/bin/echo "$((n += 1))"

Isso não é um subshell, o comando será avaliado no ambiente atual de execução do shell, a variável n do ambiente atual de execução do shell será incrementada, mas o shell irá 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 porque não executam um processo filho para executar esse comando externo se este for o último comando de um script ou de um subshell (para as subshells implementadas como processos-filhos). ( bash , no entanto, só faz isso se esse comando for o único comando da subshell).

O que isso significa é que, com esses shells, se o último comando na subshell for um comando externo, o subshell não causará a geração de um processo extra. Se você comparar:

a=1; /bin/echo "$a"; a=2; /bin/echo "$a"

com

a=1; /bin/echo "$a"; (a=2; /bin/echo "$a")

haverá o mesmo número de processos criados, somente no segundo caso, a segunda bifurcação é feita antes para que o a=2 seja executado em um ambiente de subshell.

    
por 31.01.2018 / 18:42
1

Subshell

O shell filho também é chamado de subshell. Subshell pode ser criado a partir do shell pai e de outro shell. Subshell pode ser criado usando:
1. Lista de processos :
Uma lista de processos é um agrupamento de comandos entre parênteses.Exemplo

( pwd ; (echo $BASH_SUBSHELL)) 

isto irá imprimir o diretório de trabalho atual e o número de shell gerado. OBSERVAÇÃO Invocar subshell é caro.
2. Cocprocess
Ele gera um subshell no modo background e executa um comando dentro desse subshell.

coproc sleep 10

se você digitar o comando jobs

[1]+  Running                 coproc COPROC sleep 10 &

você verá o sono como um processo em segundo plano em execução em segundo plano.

Bifurcando um Processo Infantil

Um processo filho na computação é um processo criado por outro processo. Sempre que um comando externo é executado, um processo filho é criado. Esta ação é denominado bifurcação.

$ps -f
UID        PID  PPID  C STIME TTY          TIME CMD  
umcr7     3647  3638  0 13:54 pts/0    00:00:00 bash
umcr7     3749  3647  0 13:59 pts/0    00:00:00 ps -f

Como ps -f é o comando externo (ou seja, um comando externo, às vezes chamado de comando do sistema de arquivos, é um programa que existe fora do shell bash. ) isto irá criar o processo filho com o id pai do shell bash a partir do qual ele é executado.

    
por 21.11.2018 / 10:34