2010-07-05 4 views
5

Wie Sie eine Funktion in der Bash schreiben, die den Befehl ausführt, dass es als Argument angegeben wird, woBash Funktion Befehl Aufruf als Argument angegeben

  • Der gegebene Befehl ein Alias ​​
  • Argumente sein sein muss genau wie gegeben weitergegeben; keine

Mit anderen Worten erfolgt Auswerten kann, wie eine als transparente-as-möglich Wrapper Funktion zu schreiben.

Das Ziel der Wrapper-Funktion könnte zum Beispiel sein, das aktuelle Verzeichnis vor und nach dem gegebenen Befehl zu setzen und/oder Umgebungsvariablen zu setzen, oder Zeit wie lange der gegebene Befehl dauert, ... Als ein einfaches Beispiel hier Ich nehme eine Funktion, die nur eine Zeile ausgibt und dann den angegebenen Befehl ausführt.

Ein erster Versuch:

function wrap1 { 
    echo Starting: "[email protected]" 
    "[email protected]" 
} 

Sie es wie wrap1 echo hello nutzen könnten. Aber das Problem ist, Sie können alias myalias echo nicht tun und dann wrap1 myalias hello aufrufen: Es würde den Alias ​​nicht auflösen.

Ein weiterer Versuch mit eval:

function wrap2 { 
    echo Starting: "[email protected]" 
    eval "[email protected]" 
} 

nun ein Alias ​​Werke aufrufen. Aber das Problem ist, dass es auch die Argumente bewertet. Zum Beispiel wrap2 echo "\\a" druckt nur a anstelle von \a, weil die Argumente zweimal ausgewertet werden.

shopt -s expand_aliases scheint hier auch nicht zu helfen.

Gibt es eine Möglichkeit, Aliase wie wrap2 auszuwerten, aber die Argumente trotzdem wie wrap1 weiterzugeben?

+1

Ihre erste Funktion ist der Weg zu gehen. Geben Sie Aliase nicht richtig ab. ["Für fast jeden Zweck werden Shell-Funktionen gegenüber Aliasen bevorzugt."] (Http://www.gnu.org/software/bash/manual/html_node/Aliases.html#Aliases) –

+0

[Erforderlich] (http://mywiki.wooledge.org/BashFAQ/050) –

Antwort

7

Sie (äh, ich) können printf% q verwenden, um den Argumenten zu entkommen. Auf den ersten Blick ergibt das Entkommen mit printf und dann das Ausführen von eval immer dasselbe Ergebnis wie das direkte Übergeben der Argumente.

wrap() { 
    echo Starting: "[email protected]" 
    eval $(printf "%q " "[email protected]") 
} 
+0

Was ist 'command = $ (shift)'? AFAIK 'shift' schreibt nicht auf stdout. – Philipp

+0

Aber 'printf"% q "' sieht sehr vielversprechend aus. Funktioniert das auch für indirekte oder rekursive Aliase? – Philipp

+0

Awtch, der $ (shift) war natürlich falsch. Behoben. In der Tat gibt es überhaupt keinen Grund, zwischen dem ersten "Wort" (möglicherweise dem Alias) und dem Rest des Befehls überhaupt zu unterscheiden. –

0

Es scheint, mit einem Doppel eval möglich:

eval "eval x=($(alias y | cut -s -d '=' -f 2))" 
# now the array x contains the split expansion of alias y 
"${x[@]}" "${other_args[@]}" 

Vielleicht Ihre Funktion wie folgt geschrieben werden:

wrap() { 
    eval "eval prefix=($(alias $1 | cut -s -d '=' -f 2))" 
    shift 
    "${prefix[@]}" "[email protected]" 
} 

Allerdings ist eval Böse und Doppel eval doppelt böse und Aliasnamen werden in Skripts aus einem bestimmten Grund nicht erweitert.

+0

Ich stimme zu, dass das Erweitern von Aliasen in einem Skript normalerweise keine gute Idee ist, da Sie nicht möchten, dass ein Alias ​​des Benutzers ändert, was ein Befehl in einem Skript tut. Aber das ist hier nicht relevant, weil der Befehl, mit dem ich versuche, den Alias ​​zu erweitern, kein Befehl des Skripts ist, sondern ein Befehl, der vom Benutzer eingegeben wird. –

+0

Ich nehme an, du meintest "alias $ 1" anstelle von "alias y" in wrap(). Was das tut, ist im Grunde Alias-Auflösung neu zu implementieren. Ich hoffe, dass das vermieden werden kann, aber wenn es wirklich keinen anderen Weg gibt, könnte dieser Ansatz tatsächlich funktionieren, danke. Um die Lösung zu vervollständigen, müsste es sich auch mit Befehlen beschäftigen, die keine Aliase sind, Aliase, die auf andere Aliase auflösen, rekursive Aliase, ... Ich fürchte, das würde zu einem ziemlich großen Biest werden. –

+0

Danke, korrigiert 'y' →' $ 1'. – Philipp