AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 496341
Accepted
studog
studog
Asked: 2019-01-24 14:28:01 +0800 CST2019-01-24 14:28:01 +0800 CST 2019-01-24 14:28:01 +0800 CST

Por que o POSIX requer que certos embutidos do shell tenham uma implementação externa?

  • 772

A partir desta pergunta sobre se printf é um built-in para yash , vem esta resposta que cita o padrão POSIX .

A resposta aponta que a sequência de pesquisa POSIX é encontrar uma implementação externa do comando desejado e, em seguida, se o shell o implementou como interno, execute o interno. (Para built-ins que não são built-ins especiais .)

Por que o POSIX tem esse requisito para que uma implementação externa exista antes de permitir que uma implementação interna seja executada?

Parece... arbitrário, então estou curioso.

shell posix
  • 4 4 respostas
  • 1974 Views

4 respostas

  • Voted
  1. Best Answer
    JdeBP
    2019-01-24T20:51:04+08:002019-01-24T20:51:04+08:00

    Esta é uma regra "como se".

    Simplificando: o comportamento do shell como os usuários veem não deve mudar se uma implementação decidir tornar um comando externo padrão também disponível como shell embutido.

    O contraste que mostrei em https://unix.stackexchange.com/a/496291/5132 entre os comportamentos (por um lado) dos shells PD Korn, MirBSD Korn e Heirloom Bourne; (por outro lado) os shells Z, 93 Korn, Bourne Again e Debian Almquist; e (na mão que agarra) a concha de Watanabe destaca isso.

    Para os shells que não possuem printfum built-in, removendo /usr/binde PATHfaz uma invocação de printfparar de funcionar. O comportamento conforme POSIX, exibido pelo shell Watanabe em seu modo conforme, causa o mesmo resultado. O comportamento do shell que possui um printfbuilt-in é como se estivesse invocando um comando externo.

    Considerando que o comportamento de todos os shells não conformes não se altera se /usr/binfor removido de PATH, e eles não se comportam como se estivessem invocando um comando externo.

    O que o padrão está tentando garantir a você é que os shells podem incorporar todos os tipos de comandos normalmente externos (ou implementá-los como suas próprias funções de shell), e você ainda obterá o mesmo comportamento dos built-ins que você fez com os comandos externos se você ajustar PATHpara impedir que os comandos sejam encontrados. PATHcontinua sendo sua ferramenta para selecionar e controlar quais comandos você pode invocar.

    (Como explicado em https://unix.stackexchange.com/a/448799/5132 , anos atrás, as pessoas escolhiam a personalidade de seu Unix alterando o que estava acontecendo PATH.)

    Pode-se opinar que fazer o comando sempre funcionar, independentemente de ele ser encontrado, PATH é, na verdade, o objetivo de criar comandos normalmente externos embutidos. (É por isso que meu conjunto de ferramentas nosh ganhou um printenvcomando embutido na versão 1.38, na verdade. Embora isso não seja um shell.)

    Mas o padrão está lhe dando a garantia de que você verá o mesmo comportamento para comandos externos regulares que não estão no PATHshell, como você verá em outros programas não shell invocando a execvpe()função, e o shell não será magicamente capaz de execute (aparentemente) comandos externos comuns que outros programas não podem encontrar com o mesmo arquivo PATH. Tudo funciona de forma auto-consistente do ponto de vista do usuário e PATHé a ferramenta para controlar como funciona.

    Leitura adicional

    • Por que os utilitários obrigatórios POSIX não estão embutidos no shell?
    • Por que o echo é um shell embutido no comando?
    • Como o bash executa comandos
    • 16
  2. mosvy
    2019-01-24T15:44:57+08:002019-01-24T15:44:57+08:00

    Isso é bastante absurdo e é por isso que nenhum shell o está implementando em seu modo padrão.

    A lógica do padrão e seu exemplo ilustrativo sugerem que esta foi uma tentativa fracassada de ter um built-in regular associado a um caminho, e deixar o usuário substituí-lo por ter seu próprio binário aparecendo antes dele PATH(por exemplo, um printfbuilt-in associado com /usr/bin/printfpode ser substituído pelo /foo/bin/printfcomando externo definindo PATH=/foo/bin:$PATH).

    No entanto, o padrão acabou não exigindo isso, mas algo completamente diferente (e também inútil e inesperado).

    Você pode ler mais sobre isso neste relatório de bug . Citando do texto final aceito :

    Muitas implementações existentes executam um built-in regular sem realizar uma pesquisa PATH. Esse comportamento não corresponde ao texto normativo e não permite que os autores de script substituam os utilitários internos regulares por meio de um PATH especialmente criado. Além disso, a justificativa explica que a intenção é permitir que os autores substituam os built-ins modificando o PATH, mas não é isso que diz o texto normativo .

    FWIW, também não acho que haja nenhum shell implementando os requisitos revisados ​​do texto aceito.

    • 15
  3. A. Hendry
    2021-05-26T15:21:50+08:002021-05-26T15:21:50+08:00

    Acompanhamento vis-a-vis echovs printf:

    (Abaixo, builtin significa "embutido especial" e "embutidos regulares" não são considerados embutidos por mim, pois não são embutidos no shell)

    O primeiro comitê de padronização do POSIX não conseguiu concordar em como padronizar o echo, então eles se comprometeram ao emitir que se fossem passados ​​sinalizadores ( -e,-n,-E, etc. \n,\c,\t) o shell de implementação em vez de POSIX. Em vez disso, o printfcomando foi adicionado e recebeu um comportamento bem definido. (fonte: Classic Shell Scripting, de Robbins e Beebe).

    Embora printfseja bem definido, alguns shells não possuem printfcomo comando embutido (ex mksh. ). Em vez disso, eles usam printffrom /usr/bin/. Isso significava que todos os scripts executados a partir desse shell imprimiriam o mesmo em um determinado sistema operacional (Ubuntu, Fedora, etc.), mas não necessariamente imprimiriam o mesmo em todos os sistemas operacionais (na verdade, muitos usuários alteraram o printfpara /usr/binisso razão).

    Alternativamente, shells com printfbuiltin imprimiriam o mesmo independentemente do sistema operacional, mas apenas se usados ​​como implementados para o shell. No entanto, como printfo comportamento é definido pelo padrão POSIX, isso não é necessariamente uma preocupação para os programadores. No entanto, se PATHfosse substituído por shells que usam printffrom /usr/bin/, printfnão seria encontrado.

    Embora todos os shells tenham echocomo built-in, alguns interpretam sequências de escape diretamente (por exemplo ash, ) enquanto outros (a maioria) exigem um -esinalizador: o comportamento não é definido pelo POSIX, mas pelo shell.

    Um dos principais aborrecimentos do echovs. printfé que echoimprime novas linhas no final da string por padrão, mas printfnão. printf requer a \nsequência de escape para imprimir novas linhas. Por outro lado, para evitar echoa impressão de uma nova linha, a \csequência de escape é necessária (potencialmente, exigindo também o -esinalizador).

    printférecomendado para a máxima portabilidade uma vez que o seu comportamento é definido pelo POSIX, mas pessoalmente acho que imprimir explicitamente uma nova linha no final de cada linha é bastante aborrecido (a maioria das linhas que escrevo requerem uma nova linha no final e raramente preciso suprimir echoimpressão de novas linhas). Por outro lado, echoestá sempre disponível, pois é um builtin (sem risco de não ser encontrado em $PATH) e uma simples verificação pode ser realizada para determinar se o -esinalizador é necessário e um alias correspondente echofeito:

    #! /bin/sh -
    
    # Determine if "builtin" command exists.
    BUILTIN='builtin'
      
    if ! ("${BUILTIN}" echo 123 >/dev/null 2>&1); then
      BUILTIN=''
    fi
    export BUILTIN
    
    ECHO='echo -e'
    
    if ${BUILTIN} [ "`echo -e test`" = '-e test' ]; then
      ECHO='echo'
    fi
    export ECHO
    
    # Now use "${ECHO}" where you would normally use "echo"...
    

    Pessoalmente, prefiro fazer isso e só usar printfse precisar de formatação especial.

    ATUALIZAÇÃO: Devo dar o devido crédito onde o crédito é devido. O código do shell acima foi retirado diretamente do shunit2. O crédito vai para Kate Ward e a shunit2equipe de desenvolvimento por isso! (Bem feito ;) )

    • 3
  4. A. Hendry
    2021-05-27T20:47:14+08:002021-05-27T20:47:14+08:00

    Adicionando isso também ( Classic Shell Scripting de Robbins e Beebe é um ótimo livro):

    O shell tem vários comandos embutidos. Isso significa que o próprio shell executa o comando, em vez de executar um programa externo em um processo separado. Além disso, o POSIX distingue entre built-ins “especiais” e built-ins “regulares”. [A maioria dos built-ins regulares] precisa ser embutido para que o shell funcione corretamente (por exemplo, read). Outros são normalmente embutidos no shell apenas para eficiência (por exemplo, truee false). O padrão permite que outros comandos sejam embutidos para eficiência também, mas todos os embutidos regulares devem ser acessíveis como programas separados que podem ser executados diretamente por outros programas binários.A distinção entre comandos internos especiais e regulares entra em jogo quando o shell procura comandos a serem executados. A ordem de pesquisa de comando é primeiro os internos especiais, depois as funções do shell, depois os internos regulares e, finalmente, os comandos externos encontrados pesquisando os diretórios listados em $PATH. Essa ordem de pesquisa torna possível definir funções de shell que estendem ou substituem as funções de shell regulares. Esse recurso é usado com mais frequência em shells interativos. Por exemplo, suponha que você queira que o prompt do shell contenha o último componente do nome do caminho do diretório atual. A maneira mais fácil de fazer isso acontecer é fazer com que o shell seja alterado PS1toda vez que você alterar os diretórios. Você poderia simplesmente escrever sua própria cdfunção [ ] [para isso].Há uma pequena mosca na pomada aqui. Como a função shell acessa a funcionalidade do comando "real" cd?...O que é necessário é uma "escotilha de escape" que diga ao shell para ignorar a busca por funções e acessar o comando real. Este é o trabalho do commandcomando embutido.

    [No entanto] o commandcomando não é um comando embutido especial! Ai do programador shell que define uma função chamada command! O padrão POSIX fornece as duas qualidades especiais adicionais a seguir para os comandos integrados especiais:

    1. Um erro de sintaxe em um utilitário interno especial pode fazer com que um shell executando esse utilitário seja abortado, enquanto um erro de sintaxe em um utilitário interno regular não fará com que um shell executando esse utilitário seja abortado. Se um utilitário interno especial encontrando um erro de sintaxe não abortar o shell, seu valor de saída deve ser diferente de zero.
    2. As atribuições de variáveis ​​especificadas com utilitários integrados especiais permanecem em vigor após a conclusão do integrado; este não deve ser o caso de um utilitário regular embutido ou outro. [Ou seja] você pode especificar a atribuição de variável na frente de um comando e a variável terá esse valor apenas no ambiente do comando executado, sem afetar a variável no shell atual ou comandos subsequentes. (por exemplo PATH=/bin:/usr/bin: awk '...', ) No entanto, quando tal atribuição é usada com um comando interno especial, a atribuição permanece em vigor a partir de então, mesmo após a conclusão do interno especial.

    Arnold Robbins e Nelson HF Beebe. Shell Scripting Clássico: Comandos Ocultos que Desbloqueiam o Poder do Unix (p. 262-5). Mídia O'Reilly. Edição Kindle.

    Observe que o commandcomando faz com que o shell trate o comando e os argumentos especificados como um comando simples, suprimindo a pesquisa de função do shell. Dos Documentos IBM

    Normalmente, quando um / (barra) não precede um comando (indicando um caminho específico), o shell localiza um comando pesquisando nas seguintes categorias:

    funções de shell integradas de shell especiais variáveis ​​de ambiente PATH integradas de shell Por exemplo, se houver uma função com o mesmo nome de uma built-in regular, o sistema usará a função. O comando command permite que você chame um comando que tenha o mesmo nome de uma função e obtenha o comando simples.

    Os comandos command -v e command -V gravam na saída padrão qual nome de caminho será usado pelo shell e como o shell interpreta o tipo de comando (integrado, função, alias e assim por diante). Como os sinalizadores -v e -V produzem saída em relação ao ambiente shell atual, o comando command é fornecido como um shell Korn ou um comando interno regular do shell POSIX. O comando /usr/bin/command pode não produzir resultados corretos, porque é chamado em um subshell ou ambiente de execução de comando separado. No exemplo a seguir, o shell não consegue identificar aliases, sub-rotinas ou comandos especiais do shell:

    (PATH = comando foo -v) comando nohup -v

    Assim, no meu exemplo anterior, usei o bash builtinem vez de commandporque se eu o colocasse em um subshell, ele não funcionaria corretamente.

    Eu apoio @mosvy: parece que o texto padrão e normativo não combinam (muito absurdo mesmo).

    • 1

relate perguntas

  • Como funciona este comando? mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc -l 1234 > /tmp/f

  • FreeBSD's sh: funções de lista

  • Existe uma maneira de fazer ls mostrar arquivos ocultos apenas para determinados diretórios?

  • o que grep -v grep faz

  • Como salvar um caminho com ~ em uma variável?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve