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 / 454553
Accepted
jeremysprofile
jeremysprofile
Asked: 2018-07-11 11:18:16 +0800 CST2018-07-11 11:18:16 +0800 CST 2018-07-11 11:18:16 +0800 CST

Bash shadow a command - função com o mesmo nome do comando [duplicado]

  • 772
Essa pergunta já tem respostas aqui :
Executando um executável em PATH com o mesmo nome de uma função existente (3 respostas)
Fechado há 4 anos .

Eu tenho uma função no meu .bashrcpara sudo automaticamente para abrir arquivos que não são graváveis ​​por mim:

vim() {
    if [ -w "$1" ]; then
        \vim "$1"
    else
        sudo env HOME="$HOME" \vim -u ~/.vimrc "$1"
    fi
}

Quando o arquivo precisa de sudo, funciona bem. Quando isso não acontece, ele chama recursivamente esta função e usa 100% de 1 CPU até I CC.

A partir desta resposta , vejo que existem algumas opções, todas as quais tentei. Um realmente funciona:

'vim' "$1" #fails
\vim "$1" #fails
command vim "$1" #Works!

Por que as outras opções não funcionam como eu esperava?

(Eu sei que isso é uma duplicata, mas foi muito difícil encontrar minha resposta no SO/SE com os títulos das perguntas atuais, então eu queria postar uma pergunta com um título que eu e outros poderíamos encontrar pesquisando no google)

bash command
  • 3 3 respostas
  • 5025 Views

3 respostas

  • Voted
  1. Best Answer
    jeremysprofile
    2018-07-11T11:18:16+08:002018-07-11T11:18:16+08:00

    Qualquer caractere na frente de um alias impedirá que o alias seja acionado:

    alias ls='ls -la'
    ls foo.txt     #will run ls -la foo.txt
    \ls foo.txt    #will run ls foo.txt
    'ls' foo.txt   #will run ls foo.txt
    'ls foo.txt'   #will run ls foo.txt
    

    No entanto, isso não interrompe as funções e você precisa commandfazer referência ao interno subjacente se criar uma função com o mesmo nome.

    ls () {
        echo "not an alias"
    }
    alias ls='echo "an alias"'
    
    ls foo.txt          #will echo "an alias"
    \ls foo.txt         #will echo "not an alias"
    'ls' foo.txt        #will echo "not an alias"
    command ls foo.txt  #will actually run `ls`
    

    Explicação

    O problema é que as duas primeiras opções só podem lidar com aliases. Eles não são operadores de redirecionamento especiais que podem detectar se você tem uma função ou comando com o mesmo nome. Tudo o que eles fazem é colocar algo na frente do alias, pois os aliases só se expandem se forem a primeira parte de um pipe ou comando

    alias v='sudo vim'
    v x.txt
    #automatically expands "v" to "sudo vim" and then does the rest of the command
    # v x.txt ==> sudo vim x.txt
    

    Bash apenas tenta expandir a primeira palavra de um comando usando a lista de aliases que ele conhece (que você pode obter com alias). Os aliases não aceitam argumentos e podem ser apenas a primeira palavra (separada por espaços; vim x.txt não será expandida sudo vimim x.txtusando o alias acima) em um comando para expandir corretamente.

    No entanto, a expansão nunca acontece com aspas simples: echo '$USER'imprimirá um literal $USERe não o que a variável representa. Além disso, o bash se expande \xpara ser x(principalmente). Essas não são formas extras adicionadas especificamente para escapar de um alias, elas são apenas parte de como a expansão do bash foi escrita. Assim, você pode usar esses métodos para permitir que um alias sombreie um comando e ainda tenha acesso ao comando real.

    • 13
  2. user232326
    2018-07-11T18:42:19+08:002018-07-11T18:42:19+08:00

    Por que as outras opções não funcionam como eu esperava?

    Porque existem alguns detalhes na forma como uma linha de comando é executada.

    O conceito básico é que a primeira palavra de uma linha de comando é o comando que o shell irá pesquisar e tentar executar, nesta ordem :

    1. A linha de comando é dividida em metacaracteres (principalmente):

      metacaracteres
      Um caractere que, quando não citado, separa palavras. Um dos seguintes:
      | & ; ( ) < > nova linha de tabulação de espaço

    2. Se a primeira palavra sem aspas corresponder a uma palavra de alias, ela será substituída pela definição de alias. Para evitar loops, isso é executado apenas uma vez se a nova primeira palavra corresponder a um alias que está sendo expandido. Isso faz com que isso funcione sem loops:

      $ alias ls='ls -la'
      $ ls dir               # will expand to `ls -la dir`
      

      Observe que: Se o último caractere do valor do alias estiver em branco, a próxima palavra de comando após o alias também será verificada quanto à expansão do alias.

    3. Se a primeira palavra (resultante) for uma expansão (como um $var), ela será substituída (e sujeita à divisão de palavras IFS (e globing) se não for citada):

      $ var='echo -e '
      $ $var test '\twords'            # will expand to `echo -e test words`
      test    words
      
    4. A primeira palavra resultante após as expansões acima (após atribuições de variáveis ​​opcionais) será pesquisada nesta ordem:

      • builtins especiais (somente no modo POSIX)
      • funções
      • embutidos
      • comandos com hash (leia hash de ajuda)
      • comandos externos (pesquisados ​​em $PATHdirs)

      A primeira correspondência encontrada será executada.

    A ordem pode ser alterada por (para teste):

    • Para contornar apenas alias, use \testou qualquer outro tipo de expansão.
    • Para ignorar funções e aliases, use command test.
    • Para executar um builtin, use builtin test.
    • Para executar um aplicativo externo, use um caminho explícito: /bin/test.

    Assim, uma função definida como:

    $ ls(){ ls; }
    

    Será chamado em um loop infinito. Como também um script que chama a mesma primeira palavra. Algo como:

    #!/bin/bash
    $0 "$@"
    

    Reexecutará o mesmo script em um loop até que o kernel seja interrompido (se o kernel em uso tiver um limite de chamadas sucessivas para scripts).

    A ordem será mostrada executando type -a:

    $ test(){ echo test function; }
    $ alias test=test
    $ type -a
    test is aliased to `test'
    test is a function
    test ()
    {
        echo test function
    }
    test is a shell builtin
    test is /usr/bin/test
    

    A função (conforme definido na pergunta) ignorará apenas o alias, \vimmas não a função. Para ignorar alias e funções, use o comando. Esta função deve fazer o que você precisa:

    vim() {
            if [ -w "$1" ]; then
                command vim "$1"
            else
                sudo HOME="$HOME" bash -c 'command vim "$@"' _ -u ~/.vimrc "$1"
            fi
          }
    
    • 4
  3. Tim Kennedy
    2018-07-11T13:55:49+08:002018-07-11T13:55:49+08:00

    Se você fizer a função chamar o caminho completo para o vimbinário, não obterá o loop recursivo. Além disso, usando a -Hopção sudo define $HOME.

    vim() {
        if [ -w "$1" ]; then
            command vim "$1"
        else
            sudo env HOME="$HOME" \vim -u ~/.vimrc "$1"
        fi
    }
    

    Obrigado. Eu não tinha pensado nisso, mas agora eu tenho isso no meu .bashrctambém.


    EDITADO: chamada atualizada command vime sudo envem vez de sudo -h. desta forma, não há loop para ficar.

    • 2

relate perguntas

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

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

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

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 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

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 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
    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
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +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
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +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