É bacana jogar uma terminologia:
kernel = núcleo, parte interna.
shell = concha, a parte mais externa, a "casca".
Voltando lá aos bons tempos onde interface gráfica era coisa de frutinha, quando o sistema bootava, o kernel carregava o init, que fazia as tarefas de configurar o ambiente (montar sistemas de arquivo, configurar quotas, etc.) e iniciava os daemons, que é o equivalente no unix ao que no windows chamam de "serviços", ou seja, aplicações que rodam em background (sem interface direta com o console, e portanto, com o usuário), e, finalmente, os controladores de terminal (getty e equivalentes), que configuravam os terminais de texto (console local ou via porta serial; Alguém lembra nas repartições públicas daqueles terminais vt-100 com tela verde?, e zilhões de quilômetros de cabos RS-422?).
Os getty tem uma função simples: configuram os parametros do terminal, exibem a mensagem de pre-login (basicamente eles leem um arquivo chamado /etc/issue, e logam ele na tela), e leem uma unica linha digitada pelo usuario: o nome de login.
A partir daí, ele faz um exec() para o executavel /bin/login , usando o nome de login digitado.
Esse programa faz a validacao das credenciais de segurança, geralmente pedindo e validando a senha do usuário, e caso passe, ele usa (dentre outras) as chamadas de sistema fork() (para criar um processo filho), setsid() (para criar um novo grupo de processos, não vou entrar em detalhes), setuid()/setgid() (para mudar as permissoes do processo [que originalmente roda como root] para aqueles do usuário autenticado), e, finalmente, faz um exec() para o shell do sistema, ou aquele informado para o usuario, no arquivo /etc/passwd ou algo equivalente.
O processo login herda os seguintes descritores de arquivo do getty(): descritor de arquivo zero: associado ao terminal, em modo leitura; Descritores 1 & 2, associados ao terminal, em modo escrita.
Tanto o login, quanto o shell que herda dele, associam estes descritores, respectivamente, ao que na terminologia ansi c se chama por entrada padrão, saída padrão, e saída de erros padrão.
Quando a biblioteca C mapeia estes descritores aos sistemas de mais alto nível, com buffers, ela o faz criando os famosos objetos FILE * chamados, respectivamente, de stdin, stdout, e stderr.
O shell, então, roda em modo interativo, lendo comandos que o usuário passa, e executando.
Cada subprocesso que o shell cria, por exemplo, quando você chama um comando externo (grep, cat, etc.), herda estes descritores de arquivos associados ao terminal.
Mas o shell possui uma semantica interessante.
Ao inves de:
cat /etc/issue
que faria a leitura do arquivo issue, jogando a saida do comando na saida padrao, associada ao terminal, o usuario pode fazer:
cat /etc/issue >/dev/null
O que o shell faz no primeiro caso é um fork() e um exec("/bin/cat" ...), no segundo caso, ele antes abre o arquivo /dev/null e associa ele ao descritor 1, o que faz com que o cat, quando execute, jogue a saida ao arquivo /dev/null ... que nada mais é do que um dispositivo de entrada & saída cujo driver do kernel simplesmente descarta tudo que é gravado nele.
Outros recursos bacanas são os pipes:
se o usuario digita:
whoami | rev
O shell vai pegar a saida padrão do comando whoami (descritor de arquivo 1) e ligá-lo, através de um "pipe" (um mecanismo do unix que faz com que o que for gravado num descritor de arquivo, apareça para leitura em outro), ao descritor de arquivo zero que o processo rev herda. Finalmente, a saida do comando rev, como nao foi redirecionada para lugar algum, vai parar na saída padrão do terminal.
todas estas chamadas de sistema, a implementação de mecanismos de leitura e gravação de arquivos, são, salvo nos raros casos em que é apenas uma abstração provida pela libc, providos pelo kernel.
O que o shell faz é tornar boa parte desta infra-estrutura acessível ao usuário, através de comandos (diretos ou indiretos).
O bacana é que os programas no unix são independentes do shell, e vice-versa, vice? Então dá pra usar o csh, ash, bash, e uma infinidade de outras coisas. Tinha um usuário com conta num provedor onde trabalhei que usava o tclsh, o que considero uma heresia digna de ir pra fogueira, infelizmente pra mim, o unix surgiu bem depois da inquisição e eu não fazia parte de nenhum comitê inquisitor.
Sou contra a pena de morte, mesmo em casos de barbárie, mas pra quem usar tclsh, eu abro uma exceção
