Por que “ls” requer um processo separado para execução?

14

Por que ls exige um processo separado para sua execução? Eu sei o motivo pelo qual comandos como cd não podem ser executados pelo mecanismo de bifurcação, mas há algum dano se ls for executado sem bifurcação?

    
por crisron 10.01.2014 / 04:45

6 respostas

18

A resposta é mais ou menos que ls é um executável externo. Você pode ver sua localização executando type -p ls .

Por que não é ls embutido no shell? Bem, por que deveria ser? O trabalho de um shell não é abranger todos os comandos disponíveis, mas fornecer um ambiente capaz de executá-los. Algumas shells modernas têm echo , printf e suas características como builtins, que não são tecnicamente construídas, mas são feitas por razões de desempenho quando são executadas repetidamente (principalmente em laços apertados). Sem torná-los construídos, o shell teria que bifurcar e executar um novo processo para cada chamada a eles, o que poderia ser extremamente lento.

No mínimo, a execução de ls , um executável externo, requer a execução de uma das famílias de exec de chamadas do sistema. Você poderia fazer isso sem bifurcar, mas substituiria o shell principal que você está usando. Você pode ver o que acontece nessa instância fazendo o seguinte:

exec ls; echo "this never gets printed"

Como a imagem do processo do seu shell é substituída, o shell atual não está mais acessível depois de fazer isso. Para que o shell possa continuar a rodar após executar ls, o comando teria que ser construído no shell.

O bifurcação permite a substituição de um processo que não é seu shell principal, o que significa que você pode continuar a executar seu shell posteriormente.

    
por 10.01.2014 / 04:52
15

O Manual de referência da Bash declara:

Builtin commands are necessary to implement functionality impossible or inconvenient to obtain with separate utilities.

Ou seja, as shells são projetadas para somente incluir comandos internos se:

  1. Requerido pelo padrão POSIX
  2. Comandos que requerem acesso ao próprio shell, como internos do controle de tarefas
  3. Comandos que são muito simples, não dependem do sistema operacional e aumentam a eficiência de execução quando implementados como internos, como printf

O comando ls não se ajusta a nenhum dos requisitos acima.

No entanto , aqui não há restrição de programação que impeça ls de ser implementado como um built-in, que está sendo executado no mesmo processo que o intérprete bash. As razões de design para os comandos não sendo implementados como internos do shell são:

  1. O shell deve ser separado do sistema de arquivos - nenhum comando interno deve depender da operação correta de qualquer sistema de arquivos ou dispositivos periféricos
  2. Um comando que pode ser do tipo de sistema de arquivos ou dependente do sistema operacional deve ser um executável separado
  3. Um comando para o qual você pode querer ir ou voltar deve ser um processo separado
  4. Um comando que você pode querer executar em segundo plano deve ser um executável separado
  5. Um comando que possui um grande número de parâmetros possíveis é melhor implementado em um executável separado
  6. Os comandos que devem ter a mesma saída, independentemente de qual tipo de shell (bash, csh, tsh, ...) os chama devem ser executáveis independentes

Com relação ao primeiro motivo: você quer que o shell seja o mais independente e resiliante possível. Você não quer que o shell fique preso em ls de uma montagem NFS que "não está respondendo ainda tentando".

Com relação ao segundo motivo - Em muitas instâncias, você pode querer usar um shell para um sistema que usa o Busybox ou outro sistema de arquivos que tenha uma implementação ls diferente. Ou até mesmo usar a mesma fonte de shell em sistemas operacionais que têm implementações ls diferentes.

Em relação à terceira razão - Para expressões como find . -type d | xargs ls -lad , seria difícil ou impossível implementar o ls no mesmo processo que o interpretador de shell.

Com relação à quarta razão - alguns comandos ls podem demorar muito para serem concluídos. Você pode querer que o shell continue fazendo outra coisa nesse meio tempo.

Observação: veja esta esta postagem útil por Warren Young em resposta a uma pergunta semelhante.

    
por 10.01.2014 / 09:49
2

ls não requer um processo separado. Poucos comandos na verdade requerem um processo separado: somente aqueles que precisam alterar os privilégios.

Como regra, os shells implementam comandos como builtins somente quando esses comandos precisam ser implementados como builtins. Comandos como alias , cd , exit , export , jobs ,… precisam ler ou modificar algum estado interno do shell e, portanto, não podem ser programas separados. Comandos que não possuem tais requisitos podem ser comandos separados; Desta forma, eles podem ser chamados de qualquer shell ou outro programa.

Olhando para a lista de builtins no bash, apenas os seguintes builtins podem ser implementados como comandos separados. Para alguns deles, haveria uma pequena perda de funcionalidade.

  • command - mas perderia sua utilidade em situações em que PATH pode não estar configurado corretamente e o script está usando command como parte da configuração.
  • echo - é um recurso para eficiência.
  • help - poderia usar um banco de dados separado, mas incorporar o texto de ajuda no executável shell tem a vantagem de tornar o shell executável independente.
  • kill - há duas vantagens em ter um embutido: ele pode reconhecer designações de trabalho além de processar IDs e pode ser usado mesmo quando não há recursos suficientes para iniciar um processo separado.
  • printf - pelo mesmo motivo que echo , e também para suportar a opção -v para colocar a saída em uma variável.
  • pwd - o builtin oferece o recurso adicional de rastreamento de diretório atual lógico (deixando os links simbólicos intactos em vez de expandi-los).
  • test - é um built-in de eficiência (e o bash também faz alguma mágica com arquivos chamados /dev/fd/… em alguns sistemas operacionais).

Algumas conchas oferecem um número significativo de recursos adicionais. Há sash , que é um shell projetado para ser um binário independente para reparos de emergência (quando alguns comandos externos podem não ser utilizável). Ele tem um ls embutido, chamado -ls , além de outras ferramentas, como -grep e -tar . Os builtins do Sash têm menos recursos que os comandos completos. O Zsh oferece alguns recursos similares em seu módulo zsh / files . Ele não tem ls , mas a expansão de curingas ( echo * ) e zstat pode ter uma função semelhante.

    
por 11.01.2014 / 04:07
2

Eu acho que algo que as pessoas estão perdendo aqui é a complexidade de cisalhamento do programa GNU ls no Linux. Comparando o tamanho do executável de ls com os bash e dash shells no meu sistema Debian, vemos que ele é bem grande:

graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30  2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls

A inclusão de um ls como um recurso completo como a versão GNU em bash aumentaria o tamanho do executável em 10%. É quase do mesmo tamanho que o% completodash shell!

A maioria dos built-in de shell são escolhidos porque se integram ao shell de uma maneira que os executáveis externos não podem (a questão aponta cd , mas outro exemplo é a versão bash de kill integrando com o controle de tarefa bash) ou porque são comandos muito simples de implementar, oferecendo uma grande velocidade versus tamanho de retorno ( true e false são o mais simples possível).

O GNU ls teve um longo ciclo de desenvolvimento e os implementos podem oferecer opções para personalizar o que / como os resultados são exibidos. Usar um ls embutido por padrão perderia essa funcionalidade ou aumentaria significativamente a complexidade e o tamanho do shell.

    
por 10.01.2014 / 16:35
1

cd está embutido no shell, ls é um programa separado que você verá em /bin/ls .

    
por 10.01.2014 / 04:52
0

Isso faz o que você está procurando:

printf "%s\n" *

Além disso, você pode armazenar nomes de arquivos na matriz:

files=('printf "%s\n" *')  #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done

Mas não se importa com espaços em nomes
Isso passa a variável e se preocupa com espaços:

printf "%s\n" * | while read a; do echo $a; done
    
por 15.01.2014 / 11:06