Ich habe eine Shell-Funktion definiert (nennen wir sie clock
), die ich als Wrapper für einen anderen Befehl verwenden möchte, ähnlich der time
Funktion, z clock ls -R
.
Meine Shell-Funktion führt einige Aufgaben aus und endet dann mit exec "$@"
.
Ich möchte, dass diese Funktion auch mit integrierten Shell-Funktionen funktioniert, z. B. clock time ls -R
sollte das Ergebnis der time
integrierten Shell und nicht der /usr/bin/time
ausführbaren Datei ausgegeben werden . Am Ende wird jedoch exec
immer der Befehl ausgeführt.
Wie kann ich meine Bash-Funktion als Wrapper verwenden, der auch integrierte Shell-Argumente als Argumente akzeptiert?
Bearbeiten : Ich habe gerade erfahren, dass dies time
kein eingebauter Bash ist, sondern ein spezielles reserviertes Wort, das sich auf Pipelines bezieht. Ich bin immer noch an einer Lösung für integrierte Funktionen interessiert, auch wenn diese nicht funktioniert time
, aber eine allgemeinere Lösung wäre noch besser.
quelle
exec bash -c \' "$@" \'
. Sofern Ihr Befehl im ersten Parameter nicht als Shell-Skript erkannt wird, wird er als Binärdatei interpretiert, die direkt ausgeführt wird. Alternativ und einfacher, verpassen Sie einfach dasexec
und rufen Sie"@"
von Ihrer ursprünglichen Shell aus an.Antworten:
Sie haben eine Bash-Funktion definiert. Sie befinden sich also bereits in einer Bash-Shell, wenn Sie diese Funktion aufrufen. Diese Funktion könnte dann einfach so aussehen:
Diese Funktion kann mit Bash-Builtins, speziellen reservierten Wörtern, Befehlen und anderen definierten Funktionen aufgerufen werden:
Ein Alias:
Ein Bash eingebaut:
Eine weitere Funktion:
Eine ausführbare Datei:
quelle
$@
undexec $@
, wenn ich weiß, dass ich einen tatsächlichen Befehl ausführe?exec
ersetzt der Befehl die Shell. Daher gibt es keine eingebauten, Aliase, speziellen reservierten Wörter, definierten Wörter mehr, da die ausführbare Datei über einen Systemaufruf ausgeführt wirdexecve()
. Dieser Systemaufruf erwartet eine ausführbare Datei.exec $0
wenn es einen einzigen Prozess gibt, während es$@
noch zwei gibt.$@
hat die laufende Shell als übergeordneten und den Befehl als untergeordneten Prozess. Wenn Sie jedoch integrierte Funktionen, Aliase usw. verwenden möchten, müssen Sie die Shell beibehalten. Oder starten Sie eine neue.Die einzige Möglichkeit, eine integrierte Shell oder ein Shell-Schlüsselwort zu starten, besteht darin, eine neue Shell zu starten, da exec "die Shell durch den angegebenen Befehl ersetzt". Sie sollten Ihre letzte Zeile ersetzen durch:
Dies funktioniert sowohl mit eingebauten als auch mit reservierten Wörtern. Das Prinzip ist das gleiche.
quelle
Wenn der Wrapper vor dem angegebenen Befehl Code einfügen muss, funktioniert ein Alias, da er sehr früh erweitert wird:
Aliase werden fast wörtlich anstelle des Alias-Wortes eingefügt, daher
;
ist das Nachstellen wichtig - esclock time foo
erweitert sich aufdo this; do that; time foo
.Sie können dies missbrauchen, um magische Aliase zu erstellen, die sogar das Zitieren umgehen.
Zum Einfügen von Code nach einem Befehl können Sie den Hook "DEBUG" verwenden.
Speziell:
Der Hook wird immer noch vor dem Befehl ausgeführt, aber wenn er zurückgegeben wird
false
, weist er bash an, die Ausführung abzubrechen (da der Hook ihn bereits über eval ausgeführt hat).Als weiteres Beispiel können Sie diesen Alias verwenden
command please
fürsudo command
:quelle
Die einzige Lösung, die ich bisher finden könnte, wäre eine Fallanalyse, um zu unterscheiden, ob das erste Argument ein Befehl, ein integriertes oder ein Schlüsselwort ist, und im letzten Fall fehlzuschlagen:
Es funktioniert jedoch nicht
time
, sodass es möglicherweise eine bessere (und präzisere) Lösung gibt.quelle