O shell é apenas um programa, embora desempenhe um papel importante no sistema. Bash, e eu diria que a maioria dos outros shells comuns, são implementados em C. As duas mais importantes chamadas de sistema nativas que são usados na criação de subprocessos são fork()
e exec()
. Essas funções geralmente são implementadas em linguagens de nível superior, incluindo o shell.
-
fork()
"Fork" cria uma cópia duplicada do processo de chamada como seu filho. É assim que virtualmente todos os processos no sistema, exceto o primeiro ( init ) começam: como cópias do processo que começou eles. A linguagem da shell não tem, na verdade, uma função
fork
, mas inclui a sintaxe para gerar subshells, que são a mesma coisa. -
exec()
Não existe realmente uma chamada
exec()
em C, mas refere-se coloquialmente a um grupo de funções relacionadas; você pode ver a lista comman 3 exec
, que geralmente começa:The exec() family of functions replace the current process image with a new process image...
E é exatamente isso que faz: substitui a definição de partes da pilha de memória do processo atual com material novo carregado de um arquivo executável (por exemplo,
/usr/bin/ls
). É por isso quefork()
é necessário primeiro na criação de um novo processo - caso contrário, o processo de chamada deixa de ser o que era e se transforma em outra coisa; nenhum novo processo seria realmente criado.
A princípio, pode parecer uma maneira absurda e ineficiente de fazer as coisas: por que não apenas ter um comando que crie um novo processo do zero? Na verdade, isso provavelmente não seria tão eficiente por alguns motivos:
-
A "cópia" produzida por
fork()
é um pouco de abstração, já que o kernel usa um copy-on - escreva o sistema ; tudo o que realmente precisa ser criado é um mapa de memória virtual. Se a cópia chamar imediatamenteexec()
, a maioria dos dados que teriam sido copiados se tivessem sido modificados pela atividade do processo nunca terão que ser copiados / criados porque o processo não faz nada que exija seu uso. -
Vários aspectos significativos do processo filho (por exemplo, seu ambiente) não precisam ser individualmente duplicados ou definidos com base em uma análise complexa do contexto, etc. Eles são apenas considerados como sendo os mesmos do processo de chamada, e este é o sistema razoavelmente intuitivo com o qual estamos familiarizados.
Para uma discussão detalhada de exatamente o que significa "copiar o ambiente" para o processo filho gerado, consulte minha resposta aqui .
If so, what about built-in commands like cd?
Elas são, novamente, implementadas apenas em C. chdir()
, como fork()
e exec()
, faz parte das extensões da plataforma Unix para o padrão C e do que é subjacente ao comando cd
do shell. De man 2 chdir
:
chdir() changes the current working directory of the calling process to the directory specified in path.
Isso não requer um subprocesso - afeta o chamador. O shell é um interpretador de tempo de execução interativo , o que significa que ele executa o código escrito na linguagem shell conforme você o alimenta. . Na maioria das vezes não precisa executar um novo processo para fazer isso, ele faz isso sozinho.