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 / computer / Perguntas / 1526229
Accepted
Kamil Maciorowski
Kamil Maciorowski
Asked: 2020-02-18 14:32:14 +0800 CST2020-02-18 14:32:14 +0800 CST 2020-02-18 14:32:14 +0800 CST

Qual é o segundo sh em `sh -c 'some shell code' sh`?

  • 772

Pergunta

Encontrei o seguinte trecho:

sh -c 'some shell code' sh …

(onde …denota zero ou mais argumentos adicionais).

Eu sei que o primeiro shé o comando. Eu sei sh -cque deve executar o código shell fornecido (ou seja some shell code). Qual é o objetivo do segundo sh?


Isenção de responsabilidade

Às vezes, uma pergunta semelhante ou relacionada aparece como uma pergunta de acompanhamento depois de sh -cser usada adequadamente em uma resposta e o autor da pergunta (ou outro usuário) deseja saber em detalhes como a resposta funciona. Ou pode ser parte de uma questão maior do tipo "o que esse código faz?". O objetivo da pergunta atual é fornecer uma resposta canônica abaixo.

A questão principal, questões semelhantes ou relacionadas abordadas aqui são:

  1. Qual é o segundo shem sh -c 'some shell code' sh …?
  2. Qual é o segundo bashem bash -c 'some shell code' bash …?
  3. O que está find-shem find . -exec sh -c 'some shell code' find-sh {} \;?
  4. Se some shell codeestivesse em um script de shell e chamássemos ./myscript foo …, fooseria referido como $1dentro do script. Mas sh -c 'some shell code' foo …(ou bash -c …) refere-se a foocomo $0. Por que a discrepância?
  5. O que há de errado em usar sh -c 'some shell code' foo …where foois um argumento "aleatório"? Em particular:

    • sh -c 'some shell code' "$variable"
    • sh -c 'some shell code' "$@"
    • find . -exec sh -c 'some shell code' {} \;
    • find . -exec sh -c 'some shell code' {} +

    Quero dizer, posso usar $0em vez de $1dentro some shell code, não me incomoda. O que de ruim pode acontecer?

Algumas das opções acima podem ser consideradas duplicatas (possivelmente duplicatas entre sites) de perguntas existentes (por exemplo , esta ). Ainda não encontrei uma pergunta/resposta que vise explicar o problema para iniciantes que desejam entender sh -c …e seu argumento extra supostamente inútil observado em respostas de alta qualidade. Esta pergunta preenche a lacuna.

shell-script sh
  • 1 1 respostas
  • 1020 Views

1 respostas

  • Voted
  1. Best Answer
    Kamil Maciorowski
    2020-02-18T14:32:14+08:002020-02-18T14:32:14+08:00

    Nota preliminar

    É bastante incomum ver sh -c 'some shell code'invocados diretamente de um shell. Na prática, se você estiver em um shell, provavelmente escolherá usar o mesmo shell (ou seu subshell) para executar some shell code. É bastante comum ver sh -cinvocados de dentro de outra ferramenta como find -exec.

    No entanto, a maior parte desta resposta é elaborada sh -ccomo um comando autônomo (o que é) porque o problema principal depende exclusivamente de sh. Mais tarde, use alguns exemplos e dicas findonde parecer útil e/ou educativo.


    Resposta básica

    Qual é o segundo shem sh -c 'some shell code' sh …?

    É uma string arbitrária. Sua finalidade é fornecer um nome significativo para usar em mensagens de aviso e erro. Aqui está, shmas pode ser foo, shell1ou special purpose shell(corretamente entre aspas para incluir espaços).

    Bash e outros shells compatíveis com POSIX funcionam da mesma maneira quando se trata de arquivos -c. Embora eu ache a documentação do POSIX muito formal para citar aqui, um trecho de man 1 bashé bastante direto:

    bash [options] [command_string | file]
    

    -c
    Se a -copção estiver presente, os comandos serão lidos a partir do primeiro argumento sem opção command_string. Se houver argumentos após o command_string, o primeiro argumento será atribuído a $0e quaisquer argumentos restantes serão atribuídos aos parâmetros posicionais. A atribuição para $0define o nome do shell, que é usado em mensagens de aviso e erro.

    No nosso caso some shell codeé o command_stringe este segundo shé "o primeiro argumento depois". Ele é atribuído $0no contexto de some shell code.

    Desta forma, o erro de sh -c 'nonexistent-command' "special purpose shell"é:

    special purpose shell: nonexistent-command: command not found
    

    e você sabe imediatamente de qual shell ele vem. Isso é útil se você tiver muitas sh -cinvocações. "O primeiro argumento após o command_string" pode não ser fornecido; nesse caso, sh(string) será atribuído $0se o shell for sh, bashse o shell for bash. Portanto, são equivalentes:

    sh -c 'some shell code' sh
    sh -c 'some shell code'
    

    Mas se você precisar passar pelo menos um argumento depois some shell code(ou seja, talvez argumentos que devam ser atribuídos a $1, $2, …) então não há como omitir aquele que será atribuído a $0.


    Discrepância?

    Se some shell codeestivesse em um script de shell e chamássemos ./myscript foo …, fooseria referido como $1dentro do script. Mas sh -c 'some shell code' foo …(ou bash -c …) refere-se a foocomo $0. Por que a discrepância?

    Normalmente, um shell que interpreta um script obtém o nome do script (por exemplo ./myscript, ) como a entrada zero na matriz de argumentos, disponível posteriormente como $0. Em seguida, o nome será usado em mensagens de aviso e erro. Normalmente, esse comportamento é perfeitamente aceitável e não há necessidade de fornecê-lo $0manualmente. Por outro lado sh -c, não há script para obter um nome. Ainda assim, algum nome significativo é útil, daí a maneira de fornecê-lo.

    A discrepância desaparecerá se você parar de considerar o primeiro argumento depois some shell codecomo um (tipo de) parâmetro posicional para o código. Se some shell codeestiver em um script nomeado myscripte você chamar ./myscript foo …, o código equivalente com sh -cserá:

    sh -c 'some shell code' ./myscript foo …
    

    Aqui ./myscriptestá apenas uma string, parece um caminho, mas esse caminho pode não existir; a string pode ser diferente em primeiro lugar. Dessa forma, o mesmo código shell pode ser usado. O shell será atribuído fooa $1em ambos os casos. Nenhuma discrepância.


    Armadilhas de tratar $0como$1

    O que há de errado em usar sh -c 'some shell code' foo …onde foo é um argumento "aleatório"? [...] Quer dizer, posso usar no $0lugar de $1dentro some shell code, não me incomoda. O que de ruim pode acontecer?

    Em muitos casos, isso funcionará. No entanto, existem argumentos contra esta abordagem.

    1. A armadilha mais óbvia é que você pode receber avisos ou erros enganosos do shell invocado. Lembre-se de que eles começarão com o que for $0expandido no contexto do shell. Considere este trecho:

      sh -c 'eecho "$0"' foo    # typo intended
      

      O erro é:

      foo: eecho: command not found
      

      e você pode se perguntar se foofoi tratado como um comando. Não é tão ruim se foofor codificado e exclusivo; pelo menos você sabe que o erro tem algo a ver com foo, então chama sua atenção para esta mesma linha de código. Pode ser pior:

      # as regular user
      sh -c 'ls "$0" > "$1"/' "$HOME" "/root/foo"
      

      A saída:

      /home/kamil: /root/foo: Permission denied
      

      A primeira reação é: o que aconteceu com meu diretório pessoal? Outro exemplo:

      find /etc/fs* -exec sh -c '<<EOF' {} \;    # insane shell code intended
      

      Saída possível:

      /etc/fstab: warning: here-document at line 0 delimited by end-of-file (wanted `EOF')
      

      É muito fácil pensar que há algo errado com /etc/fstab; ou se perguntar por que o código quer interpretá-lo como here-document.

      Agora execute esses comandos e veja a precisão dos erros quando fornecemos nomes significativos:

      sh -c 'eecho "$1"' "shell with echo" foo    # typo intended
      sh -c 'ls "$1" > "$2"/' my-special-shell "$HOME" "/root/foo"
      find /etc/fs* -exec sh -c '<<EOF' find-sh {} \;    # insane shell code intended
      
    2. some shell codenão é idêntico ao que seria em um script. Isso está diretamente relacionado à alegada discrepância elaborada acima. Pode não ser um problema; ainda em algum nível de shell-fu, você pode apreciar a consistência.

    3. Da mesma forma, em algum nível, você pode gostar de escrever scripts da maneira certa. Então, mesmo que você consiga usar $0, você não fará isso porque não é assim que as coisas deveriam funcionar.

    4. Se você deseja passar mais de um argumento ou se o número de argumentos não é conhecido antecipadamente e você precisa processá-los em sequência, usar $0para um deles é uma má ideia. $0é por design diferente de $1ou $2. Este fato se manifestará se some shell codeusar um ou mais dos seguintes:

      • $#– O número de parâmetros posicionais não leva $0em consideração porque $0não é um parâmetro posicional.

      • $@ou $*– "$@"é como "$1", "$2", …, não há "$0"nesta sequência.

      • for f do(equivalente a for f in "$@"; do) – $0nunca é atribuído a $f.

      • shift( shift [n]em geral) – Os parâmetros posicionais são alterados, $0permanecem intactos.

      Em particular, considere este cenário:

      1. Você começa com um código assim:

        find . -exec sh -c 'some shell code referring "$1"' find-sh {} \;
        
      2. Você percebe que ele executa um shpor arquivo. Isso é abaixo do ideal.

      3. Você sabe que -exec … \;substitui {}por um nome de arquivo, mas -exec … {} +substitui {}possivelmente por muitos nomes de arquivo. Você aproveita o último e introduz um loop:

        find . -exec sh -c '
           for f do
              some shell code referring "$f"
           done
        ' find-sh {} +
        

      Essa otimização é uma coisa boa. Mas se você começar com isso:

      # not exactly right but you will get away with this
      find . -exec sh -c 'some shell code referring "$0"' {} \;
      

      e transformá-lo nisso:

      # flawed
      find . -exec sh -c '
         for f do
            some shell code referring "$f"
         done
      ' {} +
      

      então você introduzirá um bug: o primeiro arquivo vindo da expansão de {}não será processado por some shell code referring "$f". Note -exec sh -c … {} +é executado shcom tantos argumentos quanto possível, mas há limites para isso e se houver muitos, muitos arquivos, então um shnão será suficiente, outro shprocesso será gerado por find(e possivelmente outro, e outro, …). Com cada um sh, você pulará (ou seja, não processará) um arquivo.

      Para testar isso na prática, substitua a string some shell code referringpor echoe execute os trechos de código resultantes em um diretório com poucos arquivos. O último snippet não será impresso ..

      Tudo isso não significa que você não deva usar $0. some shell codeVocê pode e deve usar $0para coisas para as quais foi projetado. Por exemplo, se você deseja some shell codeimprimir um aviso ou erro (personalizado), faça a mensagem começar com $0. Forneça um nome significativo depois some shell codee aproveite os erros significativos (se houver) em vez dos vagos ou enganosos.


    Dicas finais:

    • Com find … -exec sh -c … nunca embutir {}no código shell .

    • Pelas mesmas razões some shell code, não deve conter fragmentos expandidos pelo shell atual, a menos que você realmente saiba que os valores expandidos são seguros com certeza. A melhor prática é colocar aspas simples em todo o código (como nos exemplos acima, é sempre 'some shell code') e passar cada valor não fixo como um argumento separado. Tal argumento é recuperável com segurança de um parâmetro posicional dentro do shell interno. A exportação de variáveis ​​também é segura. Execute isso e analise a saída de cada um sh -c …(a saída desejada é foo';date'):

      variable="foo';date'"
      
      # wrong
      sh -c "echo '$variable'" my-sh
      
      # right
      sh -c 'echo "$1"' my-sh "$variable"
      
      # also right
      export variable
      sh -c 'echo "$variable"' my-sh
      
    • Se você executar sh -c 'some shell code' …em um shell, o shell removerá aspas simples abraçando some shell code; então o shell interno ( sh) irá analisar some shell code. É importante citar direito também neste contexto. Você pode achar isso útil: Expansão de parâmetros e aspas dentro de aspas .

    • 11

relate perguntas

  • Como encurtar uma lista de nomes de variáveis ​​no bash?

  • Como matar um pipeline depois que alguma saída ocorreu

  • Desativar arquivos temporariamente no macOs

  • Como alternar a energia da tomada para Eaton ePDU G3 a partir do shell script

  • Descritor de arquivo aberto uma vez, mas fechado muitas vezes; por que a discrepância?

Sidebar

Stats

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

    Como posso reduzir o consumo do processo `vmmem`?

    • 11 respostas
  • Marko Smith

    Baixar vídeo do Microsoft Stream

    • 4 respostas
  • Marko Smith

    O Google Chrome DevTools falhou ao analisar o SourceMap: chrome-extension

    • 6 respostas
  • Marko Smith

    O visualizador de fotos do Windows não pode ser executado porque não há memória suficiente?

    • 5 respostas
  • Marko Smith

    Como faço para ativar o WindowsXP agora que o suporte acabou?

    • 6 respostas
  • Marko Smith

    Área de trabalho remota congelando intermitentemente

    • 7 respostas
  • Marko Smith

    O que significa ter uma máscara de sub-rede /32?

    • 6 respostas
  • Marko Smith

    Ponteiro do mouse movendo-se nas teclas de seta pressionadas no Windows?

    • 1 respostas
  • Marko Smith

    O VirtualBox falha ao iniciar com VERR_NEM_VM_CREATE_FAILED

    • 8 respostas
  • Marko Smith

    Os aplicativos não aparecem nas configurações de privacidade da câmera e do microfone no MacBook

    • 5 respostas
  • Martin Hope
    CiaranWelsh Como posso reduzir o consumo do processo `vmmem`? 2020-06-10 02:06:58 +0800 CST
  • Martin Hope
    Jim Pesquisa do Windows 10 não está carregando, mostrando janela em branco 2020-02-06 03:28:26 +0800 CST
  • Martin Hope
    v15 Por que uma conexão de Internet gigabit/s via cabo (coaxial) não oferece velocidades simétricas como fibra? 2020-01-25 08:53:31 +0800 CST
  • Martin Hope
    fixer1234 O "HTTPS Everywhere" ainda é relevante? 2019-10-27 18:06:25 +0800 CST
  • Martin Hope
    andre_ss6 Área de trabalho remota congelando intermitentemente 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney Por que colocar um ponto após o URL remove as informações de login? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension Ponteiro do mouse movendo-se nas teclas de seta pressionadas no Windows? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    jonsca Todos os meus complementos do Firefox foram desativados repentinamente, como posso reativá-los? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK É possível criar um código QR usando texto? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 Altere o nome da ramificação padrão do git init 2019-04-01 06:16:56 +0800 CST

Hot tag

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help
subwaysurfers
my femboy roommate

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve