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

14

Por que lsrequer um processo separado para sua execução? Eu sei a razão pela qual comandos como cdnão podem ser executados pelo mecanismo de bifurcação, mas há algum dano se lsfor executado sem bifurcação?

crisron
fonte
1
Embora lsseja um programa externo, echo *ou echo * .*(dependendo das opções do shell) faz um bom trabalho ao listar arquivos sem bifurcar-se.
gerrit
Isso é ainda melhor: printf "% s \ n" *
Costa
Nota sobre a diversidade do shell: o tcsh possui um builtin ls-Fque funciona como ls -F. Está lá para a eficiência. Você sempre entende o -Fque geralmente é uma boa ideia. Se você especificar qualquer outra opção, ela será aplicada ao comando externo.

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 está lsembutido no shell, então? 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. Alguns shells modernos têm echo, printfe seus tipos como internos, que tecnicamente não precisam ser integrados, mas são feitos por motivos de desempenho quando são executados repetidamente (principalmente em loops apertados). Sem torná-los integrados, o shell precisaria forçar e executar um novo processo para cada chamada, o que poderia ser extremamente lento.

No mínimo, a execução ls, um executável externo, exige 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 de processo do seu shell é substituída, o shell atual não fica mais acessível depois de fazer isso. Para que o shell possa continuar executando após executar ls, o comando teria que ser incorporado ao shell.

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

Chris Down
fonte
1
Eu acho que ele está perguntando por que o ls (1) não é um recurso interno dos shells, que alguém precisaria explicar como fornecedores diferentes têm opções diferentes para o ls (1) e são capazes de consultar coisas diferentes do sistema de arquivos etc. os altos e, principalmente, os inconvenientes de tê-lo 'construído' na concha.
llua
@llua eu adicionei algumas informações sobre isso, e os casos de exceção de echo, printf, etc.
Chris Baixo
Nem sempre é claro por que algumas coisas são construídas e outras não. Por exemplo, por que cdnão é um executável externo?
FaHemem Mitha
@FaheemMitha Não é um link externo cdexecutável em sistemas operacionais compatíveis com POSIX ( ver aqui ). Se você realmente deseja chdir () no processo atual, é necessário integrá-lo no shell.
Chris Down
tornou-se um hábito o porquê de lsser externo, mas também pode ser implementado em um shell. Veja busybox.
15

O Manual de Referência do Bash declara:

Os comandos internos são necessários para implementar funcionalidades impossíveis ou inconvenientes de serem obtidas com utilitários separados.

Ou seja, os shells são projetados para incluir apenas comandos internos se:

  1. Exigido pelo padrão POSIX
  2. Comandos que requerem acesso ao próprio shell, como built-ins de controle de tarefas
  3. Comandos muito simples, não dependentes do SO e aumentam a eficiência de execução quando implementados como embutidos, como printf

O lscomando não se encaixa em nenhum dos requisitos acima.

No entanto , não há restrição de programação que impeça lsa implementação como um interno, que esteja sendo executado no mesmo processo que o interpretador do bash. Os motivos de design para os comandos não serem implementados como embutidos no 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 sistema de arquivos ou depende do sistema operacional deve ser um executável separado
  3. Um comando que você pode querer canalizar de ou para 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

Em relação ao primeiro motivo - você deseja que o shell seja o mais independente e resistente possível. Você não deseja que o shell fique preso em lsuma montagem NFS que "não está respondendo ainda está tentando".

Com relação ao segundo motivo - Em muitos casos, convém usar um shell para um sistema que usa o Busybox ou outro sistema de arquivos com uma lsimplementação diferente . Ou use a mesma fonte de shell em sistemas operacionais que possuem lsimplementações diferentes .

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

Em relação à quarta razão - alguns lscomandos podem demorar muito para serem concluídos. Você pode querer que o shell continue fazendo outra coisa enquanto isso.


Nota: Veja este post útil de Warren Young em resposta a uma pergunta semelhante.

Jonathan Ben-Avraham
fonte
Você perdeu a facilidade da saída da tubulação, se for um comando separado, e toda a programação necessária para canalizar uma primitiva de shell em um executável separado.
precisa saber é o seguinte
@BruceEdiger: Que prazer em receber um comentário do estimado BE. Obrigado! Acredito que o motivo 3 cobre seu comentário, não?
Jonathan Ben-Avraham
1
Eu estava pensando mais sobre o quão complicado seria o código fonte do próprio shell se ele tivesse que lidar com pipes para processos externos e canalizar a saída de um comando interno como a hipotética lspara um processo externo. Isso poderia ser feito, mas seria complicado.
precisa
1
Receio que a maioria, se não todos os seus 5 pontos, são discutíveis. 1: ls é (espero) independente da implementação do sistema de arquivos. Isso depende do kernel para fornecer uma interface consistente para a biblioteca e aplicativos padrão. 2: ls provavelmente é menos dependente do sistema operacional do que o shell. 3: conchas definitivamente permitem embutidos em tubulações. 4: shells definitivamente permitem que os buildins sejam executados em segundo plano. 5: isso é bastante subjetivo.
Jlliagre
1
@ JonathanBen-Avraham @BruceEdiger Os projéteis já não manejam a caixa de tubos para embutidos com subconchas? por exemplo, bashsaída alias | grep ls. inputcat /etc/passwd | while read a; do echo "$a"; done
Matt
2

lsnão requer um processo separado. Pouquíssimos comandos realmente requerem um processo separado: somente aqueles que precisam alterar privilégios.

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

Observando a lista de componentes internos no bash, apenas os seguintes componentes internos podem ser implementados como comandos separados. Para alguns deles, haveria uma leve perda de funcionalidade.

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

Algumas conchas oferecem um número significativo de componentes 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áveis). Possui um built-in lschamado -ls, assim como outras ferramentas como -grepe -tar. Os recursos internos do Sash têm menos recursos do que os comandos completos. O Zsh oferece alguns recursos similares em seu módulo zsh / files . Não possui ls, mas expansão de curinga ( echo *) e zstatpode ter uma função semelhante.

Gilles 'SO- parar de ser mau'
fonte
2

Eu acho que algo que as pessoas estão perdendo aqui é a complexidade de cisalhamento do lsprograma GNU no Linux. Comparando o tamanho do executável de lsao bashe dashconchas no meu sistema Debian, vemos que é muito 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

Incluir uma lsversão com todos os recursos da versão GNU bashaumentaria o tamanho do executável em 10%. É quase do mesmo tamanho que a dashconcha completa !

A maioria dos componentes internos do 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 da killintegração com o controle do trabalho do bash) ou porque são comandos muito simples de implementar, oferecendo uma grande recompensa por velocidade versus tamanho ( truee falseé o mais simples possível).

O GNU lsteve um longo ciclo de desenvolvimento e implementa várias opções para personalizar quais / como os resultados são exibidos. O uso de um built-in ls por padrão perderia essa funcionalidade ou aumentaria significativamente a complexidade e o tamanho do shell.

Graeme
fonte
1

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

DopeGhoti
fonte
0

Faça 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 ele não se importa com espaços em nomes.
Isso passa para variável e se preocupa com espaços:

printf "%s\n" * | while read a; do echo $a; done
Costa
fonte