Executando um executável no PATH com o mesmo nome que uma função existente

16

Às vezes, defino uma função que oculta um executável e ajusta seus argumentos ou saída. Portanto, a função tem o mesmo nome que o executável, e eu preciso de uma maneira de executar o executável a partir da função sem chamar a função recursivamente. Por exemplo, para executar automaticamente a saída de fossil diffthrough colordiffe less -Reu uso:

function fossil () {
    local EX=$(which fossil)
    if [ -z "$EX" ] ; then
        echo "Unable to find 'fossil' executable." >&2
        return 1
    fi
    if [ -t 1 ] && [ "$1" == "diff" ] ; then
        "$EX" "$@" | colordiff | less -R
        return
    fi
    "$EX" "$@"
}

Se eu tivesse certeza da localização do executável, eu poderia simplesmente digitar /usr/bin/fossil. Bash reconhece que isso /significa que o comando é um executável, não uma função. Mas como não sei a localização exata, tenho que recorrer à chamada whiche verificação do resultado. Existe uma maneira mais simples?

Petr Pudlák
fonte
1
Você diz: "O Bash reconhece que isso /significa que o comando é um executável, não uma função". Estritamente falando, isso não é verdade. No que eu acredito ser uma decisão de design horrível (e não documentada), o bash permite que os nomes de funções contenham barras. As barras simplesmente fazem /usr/bin/fossilcom que seja uma sequência diferente de fossil, portanto, quando você diz /usr/bin/fossil, não tenta executar a fossilfunção.
G-Man diz 'Reinstate Monica'

Respostas:

19

Use o commandshell interno:

bash-4.2$ function date() { echo 'at the end of days...'; }

bash-4.2$ date
at the end of days...

bash-4.2$ command date
Mon Jan 21 16:24:33 EET 2013

bash-4.2$ help command
command: command [-pVv] command [arg ...]
    Execute a simple command or display information about commands.

    Runs COMMAND with ARGS suppressing  shell function lookup, or display
    information about the specified COMMANDs.  Can be used to invoke commands
    on disk when a function with the same name exists.
homem a trabalhar
fonte
2
Mais uma opção é escapar do comando \date.
Jordanm
4
@ Jordanm, que funciona apenas para aliases. A questão era sobre funções. pastebin.com/TgkHQwbb
manatwork
3

Nos scripts, a #!linha costuma ser usada /bin/env bashpara executar o comando bash com base no caminho. (Pode ser diferente para alguns utilitários). Isso deve funcionar aqui também ...

(A commandalternativa também deve funcionar, mas pode depender de um shell específico) (Funciona no Bourne Shell no Solaris, mas na verdade é executado /bin/commandnesse caso, que é um shell embutido no Bash)

Ambos /bin/commande /bin/envestão listados no SUS, portanto, todas as implementações compatíveis devem tê-lo.

Gert van den Berg
fonte
Obrigado por apontar env. Eu estava com dúvidas sobre qual resposta eu deveria aceitar, mas como a pergunta é sobre bash , seu built-in commandé a melhor solução.
Petr Pudlák
1
No meu Linux não há commandexecutável, mas commandtambém funciona em dash, kshe zsh. Então, eu suponho que é um shell embutido não apenas no bash. pastebin.com/fi3gyNse
manatwork
Não é um buildin no Solaris 10 Bourne (também disponível como herança). As vantagens de um executável com um caminho conhecido é que ele não pode ser substituído por uma função.
Gert van den Berg
(A ausência de / bin / command pode explicar porque scripts usam /bin/envapós o hash-bang, se eles não querem codificar o caminho shell)
van den Berg Gert
3

A resposta de Gert me fez perceber que também se pode usar nicepara esse fim (na verdade, eu o coloquei em um dos meus scripts sem perceber):

$ function date() { echo 'at the end of days...'; }
$ date
at the end of days...
$ nice -n0 date
Mon Jan 21 16:45:21 CET 2013

É menos elegante que as outras respostas, mas, em algumas circunstâncias, pode ser uma opção útil.

Petr Pudlák
fonte
Você pode querer expandir para incluir uma alternativa semelhante: `which date`.
Eliah Kagan
1
@EliahKagan O problema `which something`é que, se não houver somethingexecutável, coisas infelizes podem acontecer. Por exemplo, se echoestá faltando, então `which echo` /bin/rm preciousFilefaz algo muito diferente do pretendido.
Petr Pudlák