Por que os utilitários obrigatórios do POSIX não são construídos no shell?

44

O objetivo desta pergunta é responder a uma curiosidade, não para resolver um problema específico de computação. A pergunta é: Por que os utilitários obrigatórios do POSIX não são normalmente incorporados nas implementações do shell?

Por exemplo, eu tenho um script que basicamente lê alguns pequenos arquivos de texto e verifica se eles estão formatados corretamente, mas leva 27 segundos para rodar, na minha máquina, devido a uma quantidade significativa de manipulação de strings. Essa manipulação de strings faz milhares de novos processos chamando várias utilidades, daí a lentidão. Tenho certeza de que, se alguns dos utilitários foram incorporados, ou seja, grep , sed , cut , tr e expr , o script seria executado em um segundo ou menos (com base no meu experiência em C).

Parece que haveria muitas situações nas quais a criação desses utilitários faria a diferença entre a possibilidade de uma solução no shell script ter desempenho aceitável ou não.

Obviamente, existe uma razão pela qual foi escolhido não fazer esses utilitários embutidos. Talvez ter uma versão de um utilitário em um nível de sistema evite ter várias versões desiguais daquele utilitário sendo usado por vários shells. Eu realmente não consigo pensar em muitas outras razões para manter a sobrecarga de criar tantos novos processos, e POSIX define o suficiente sobre os utilitários que não parece ser um grande problema ter implementações diferentes, desde que sejam cada POSIX compatível. Pelo menos não é um problema tão grande quanto a ineficiência de ter tantos processos.

    
por Kyle 23.02.2017 / 22:42

8 respostas

12

Não é esperado que os scripts do shell sejam executados com esse tipo de velocidade. Se você quer melhorar a velocidade do seu script, tente em perl. Se isso ainda for muito lento, você terá que passar para uma linguagem de tipo estatístico, como java ou c, ou escrever um módulo C para perl que execute as partes que são muito lentas.

O shell é o primeiro nível de prototipagem, se você puder provar o conceito com o shell, passe para uma linguagem de script melhor que possa fazer mais verificações de limites, o que levaria muitos hectares de shell.

Espera-se que um sistema operacional Unix inclua muitos pequenos programas que executam tarefas bem definidas, que compõem uma imagem maior. Isso é bom, pois compartimenta programas maiores. Dê uma olhada no qmail, por exemplo, e compare isso com o sendmail. O qmail é feito de vários programas:

link

A exploração do daemon de rede não ajudará você a explorar o gerenciador de filas.

    
por 23.02.2017 / 22:53
66

Why are POSIX mandatory utilities not built into shell?

Por ser compatível com POSIX, é necessário um requisito 1 para fornecer a maioria dos utilitários como comandos independentes.

Ter eles embutidos implicaria que eles precisam existir em dois locais diferentes, dentro e fora da casca. É claro, seria possível implementar a versão externa usando um wrapper de shell script para o builtin, mas isso prejudicaria os aplicativos que não são de shell chamando os utilitários.

Note que BusyBox tomou o caminho que você sugeriu implementando muitos comandos internamente e fornecendo a variante independente usando links para si mesmo. Um problema é que, embora o conjunto de comandos possa ser muito grande, as implementações geralmente são um subconjunto do padrão, portanto, não são compatíveis.

Note também que pelo menos ksh93 , bash e zsh vão mais longe, fornecendo métodos personalizados para o shell em execução carregar dinamicamente builtins de bibliotecas compartilhadas. Tecnicamente, nada impede que todos os utilitários POSIX sejam implementados e disponibilizados como builtins.

Finalmente, gerar novos processos tornou-se uma operação bastante rápida com sistemas operacionais modernos. Se você for realmente atingido por um problema de desempenho, pode haver algumas melhorias para que seus scripts sejam executados mais rapidamente.

1 POSIX.1-2008

However, all of the standard utilities, including the regular built-ins in the table, but not the special built-ins described in Special Built-In Utilities, shall be implemented in a manner so that they can be accessed via the exec family of functions as defined in the System Interfaces volume of POSIX.1-2008 and can be invoked directly by those standard utilities that require it (env, find, nice, nohup, time, xargs).

    
por 23.02.2017 / 23:48
8

No manual de referência BASH ,

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

Como tenho certeza de que você já ouviu falar, a filosofia do UNIX depende muito de vários aplicativos que têm funcionalidade limitada. Cada built-in tem uma razão muito boa porque é construído. Tudo o resto não é. Eu acho que uma classe de perguntas mais interessante é a seguinte: "por que exatamente é pwd embutido?"

    
por 23.02.2017 / 23:13
7

Os caras da AT & T se perguntaram a mesma coisa

Se você olhar para a história do AT & T Software Toolkit (atualmente inativo no github desde que a equipe principal saiu), isso é exatamente o que eles fizeram com o shell AT & T Korn, a.k.a. ksh93.

O desempenho sempre foi parte da motivação para os mantenedores do ksh93, e ao construir o ksh você pode escolher construir muitos utilitários POSIX comuns como bibliotecas carregadas dinamicamente. Vinculando esses comandos a um nome de diretório como /opt/ast/bin , você poderia controlar qual versão do comando seria usada, com base na posição desse nome de diretório em $PATH .

Exemplos:

cat chmod chown cksum cmp cp cut date expr fmt head join ln
mkdir mkfifo mktemp mv nl od paste rm tail tr uniq uuencode wc

A lista completa pode ser encontrada no repositório github ast .

Observe que a maioria das ferramentas ast tem sua própria proveniência e diferem strongmente das implementações mais comuns do gnu. A equipe da AT & T Research seguiu os padrões oficiais, que era o caminho para alcançar a interoperabilidade quando você não podia compartilhar código.

    
por 25.02.2017 / 12:40
6

Portanto, não mobilizamos recursos para otimizar a ferramenta original, para atender a todos os desejos específicos. Eu acho que o que precisamos explicar é quanto esse desejo específico teria custado para implementar.

POSIX defines enough about the utilities that it does not seem like much of a problem to have different implementations.

esta é uma suposição ruim: -P.

Os sistemas Post-POSIX continuam a se tornar mais poderosos e convenientes por boas razões; como um padrão pós-fato, ele nunca chega.

O Ubuntu iniciou um esforço para mudar para um shell POSIX enxuto para scripts, para otimizar o antigo processo de inicialização do System V init. Eu não estou dizendo que ele falhou, mas ele desencadeou muitos bugs que precisaram ser limpos: "bashisms", scripts que rodavam sob /bin/sh enquanto assumiam que bash estavam disponíveis.

POSIX sh não é uma boa linguagem de programação de propósito geral. Seu objetivo principal é funcionar bem como um shell interativo. Assim que você começar a salvar seus comandos em um script, lembre-se de abordar um Turing tarpit . Por exemplo. Não é possível detectar falhas no meio de um pipeline normal . bash adicionou set -o pipefail para isso, mas isso não está no POSIX.

Recursos úteis, mas não padronizados, são fornecidos por quase todos os utilitários mais complexos que true .

Para a classe de tarefa que você delineia, você pode desenhar uma linha aproximada para Awk, Perl e, atualmente, para Python. Diferentes ferramentas foram criadas e evoluíram de forma independente. Você esperaria, e. GNU Awk para ser incluído em uma libutilposixextended?

Não estou dizendo que agora temos uma abordagem universalmente melhor para a qual posso apontar. Eu tenho um fraquinho por Python. Awk é surpreendentemente poderoso, embora eu tenha sido frustrado por alguns recursos serem específicos do GNU Awk. Mas o ponto é que o processamento de grandes números de strings individualmente (presumivelmente a partir de linhas dos arquivos) não era uma meta de design do shell POSIX.

    
por 24.02.2017 / 02:09
2

Há também a questão de: Qual shell você criaria?

A maioria dos sistemas Unix / Linux tem múltiplos shells diferentes que são desenvolvidos independentemente (sh / bash / korn / ???). Se você construir as ferramentas no shell, você acabaria com uma implementação diferente dessas ferramentas para cada shell. Isso causaria sobrecarga, e você pode acabar com diferentes recursos / bugs, por exemplo, no grep, dependendo de qual shell você usou para invocá-lo.

    
por 24.02.2017 / 16:16
1

Muitos responderam bem. Pretendo apenas elogiar essas respostas. Eu acho que a filosofia do UNIX é que uma ferramenta deve fazer uma coisa e fazer isso bem. Se alguém tenta fazer uma ferramenta abrangente, isso é muito mais lugares para o fracasso. Limitar a funcionalidade dessa maneira faz com que um conjunto de ferramentas seja confiável.

Além disso, considere, se funcionalidades como sed ou grep foram embutidas no shell, seria tão fácil invocar a partir da linha de comando quando você quiser ?

Para encerrar, considere, algumas das funcionalidades que você deseja estar em BASH, estão em BASH. Por exemplo, a capacidade de correspondência de RE no BASH é implementada usando o operador binário = ~ (veja Gramática de concha na Página do Manual para mais, especificamente, faça referência à discussão do [[ ]] construir para se ). Como um exemplo muito rápido, digamos que eu esteja procurando um arquivo com dois dígitos hexadecimais:

while read line; do
    if [[ $line =~ 0x[[:xdigit:]]{2} ]]; then
        # do something important with it
    fi
done < input_file.txt

Quanto à funcionalidade sed-like , procure em Expansão de Parâmetro em o cabeçalho de Expansão da mesma página do manual. Você verá uma série de coisas que você pode fazer que lembram o sed. Na maioria das vezes, uso sed para fazer algum tipo de substituição mudar para texto. Construindo fora do acima:

# this does not take into account the saving of the substituted text
# it shows only how to do it
while read line; do
    ${line/pattern/substitution}
done < input_file.txt

No final das contas, o acima é "melhor" que?

grep -E "[[:xdigit:]]{3}" input_file.txt
sed -e 's/pattern/substitution/' input_file.txt
    
por 24.02.2017 / 17:12
1

Este é, eu acho, um acidente histórico.

Quando o UNIX foi criado no final dos anos 60 e início dos anos 70, os computadores não tinham quase tanta memória quanto hoje. Teria sido possível, na época, implementar toda essa funcionalidade como builtins de shell, mas devido a limitações de memória, eles teriam que limitar a quantidade de funcionalidade que poderiam implementar, ou arriscar sem memória e / ou trocar lixo problemas.

Por outro lado, implementando a funcionalidade especificada como programas separados e fazendo as duas chamadas de sistema necessárias para iniciar um novo processo o mais leve possível, eles podem criar um ambiente de script que não tenha esses problemas e que ainda funciona a uma velocidade razoável.

Claro, uma vez que essas coisas são implementadas como processos separados, as pessoas irão iniciá-las a partir de programas que não são , e então elas devem permanecer assim, ou de repente todo esse software começa a quebrar.

Isso não quer dizer que você não pode implementar alguma funcionalidade duas vezes, e de fato alguns shells implementam alguma funcionalidade que deveria ser um programa externo como um shell embutido; Por exemplo, o bash implementa o comando echo como um arquivo incorporado, mas também há um /usr/bin/echo

    
por 22.03.2017 / 08:38