Ausführen einer ausführbaren Datei in PATH mit demselben Namen wie eine vorhandene Funktion

15

Manchmal definiere ich eine Funktion, die eine ausführbare Datei spiegelt und deren Argumente oder Ausgabe optimiert. Die Funktion hat also den gleichen Namen wie die ausführbare Datei, und ich brauche eine Möglichkeit, wie die ausführbare Datei von der Funktion ausgeführt werden kann, ohne die Funktion rekursiv aufzurufen. Zum Beispiel, um die Ausgabe von fossil diffthrough automatisch auszuführen colordiffund less -Rich verwende:

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" "$@"
}

Wenn ich mir sicher wäre, wo sich die ausführbare Datei befindet, könnte ich sie einfach eingeben /usr/bin/fossil. Bash erkennt, dass /der Befehl eine ausführbare Datei und keine Funktion ist. Da ich den genauen Standort nicht kenne, muss ich whichdas Ergebnis abrufen und überprüfen. Gibt es einen einfacheren Weg?

Petr Pudlák
quelle
1
Sie sagen: „Bash erkennt, dass /der Befehl eine ausführbare Datei und keine Funktion ist.“ Genau genommen stimmt das nicht. In einer meiner Meinung nach schrecklichen (undokumentierten) Entwurfsentscheidung lässt bash zu, dass Funktionsnamen Schrägstriche enthalten. Die Schrägstriche einfach verursachen /usr/bin/fossileine andere sein Zeichenfolge aus fossil, so, wenn Sie sagen /usr/bin/fossil, es nicht versuchen , das auszuführen fossilFunktion.
G-Man sagt, dass Monica

Antworten:

19

Verwenden Sie die commandeingebaute Shell:

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.
Mann bei der Arbeit
quelle
2
Eine weitere Option besteht darin, den Befehl zu verlassen \date.
Jordan
4
@jordanm, das funktioniert nur für Aliase. Die Frage war über Funktionen. pastebin.com/TgkHQwbb
Manatwork
3

In Skripten wird die #!Zeile häufig verwendet /bin/env bash, um den Bash-Befehl basierend auf dem Pfad auszuführen. (Dies kann bei einigen Dienstprogrammen abweichen.) Das sollte auch hier funktionieren ...

(Die commandAlternative sollte ebenfalls funktionieren, ist jedoch möglicherweise von einer bestimmten Shell abhängig.) (Sie funktioniert auf der Bourne-Shell unter Solaris, wird jedoch /bin/commandin dem Fall ausgeführt, bei dem es sich um eine in Bash integrierte Shell handelt.)

Beide /bin/commandund /bin/envsind in SUS aufgeführt, daher sollten sie für alle kompatiblen Implementierungen verfügbar sein.

Gert van den Berg
quelle
Vielen Dank für den Hinweis env. Ich hatte Zweifel, welche Antwort ich akzeptieren sollte, aber da es sich bei der Frage um Bash handelt , commandist die integrierte Lösung die beste.
Petr Pudlák
1
Auf meinem Linux gibt es keine commandausführbare Datei, sondern commandfunktioniert auch in dash, kshund zsh. Ich gehe also davon aus, dass es sich um eine Shell handelt, die nicht nur eingebaut ist bash. pastebin.com/fi3gyNse
Manatwork
Es ist kein Build für Solaris 10 Bourne (das ist auch als heirloom-sh verfügbar). Die Vorteile einer ausführbaren Datei mit einem bekannten Pfad bestehen darin, dass sie nicht von einer Funktion überschrieben werden kann.
Gert van den Berg
(Das Fehlen des Befehls / bin / könnte erklären, warum Skripte /bin/envnach dem Hash-Knall verwendet werden, wenn sie den Shell-Pfad nicht hart codieren möchten.)
Gert van den Berg
3

Gerts Antwort ließ mich erkennen, dass man es auch nicefür den Zweck verwenden kann (ich hatte es tatsächlich in einem meiner Skripte, ohne es zu merken):

$ 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

Es ist weniger elegant als die anderen Antworten, aber unter bestimmten Umständen kann es eine nützliche Option sein.

Petr Pudlák
quelle
Sie können sie erweitern , um eine ähnliche Alternative enthalten: `which date`.
Eliah Kagan
1
@EliahKagan Das Problem mit `which something`ist, dass, wenn es keine somethingausführbare Datei gibt, unglückliche Dinge passieren können. Wenn zum Beispiel etwas echofehlt, dann `which echo` /bin/rm preciousFilegeschieht etwas ganz anderes als beabsichtigt.
Petr Pudlák