2013-07-29 11 views
6

Ich entdeckte vor kurzem einige bash Code, der die wenig bekannte verwendet (na ja, zu mir wenig bekannt sowieso) Merkmal der Funktion Umleitung, wie die stark vereinfacht:Wie können Sie Funktionsumleitung in Bash überschreiben?

function xyzzy() { 
    echo hello 
} >/dev/null 

Wenn Sie rufen Sie die Funktion mit ein einfach xyzzy, wendet es automatisch die an die Funktion angehängten Umleitungen an, unabhängig davon, was Sie beim Aufruf getan haben.

Was ich gerne wissen würde, ist, wenn es eine Möglichkeit gibt, dieses Verhalten im Aufruf der Funktion selbst zu überschreiben, um zu sehen, die Nachricht generiert wird. Ich bin zurückhaltend, um die Datei zu ändern, die alle Funktionen enthält, da (1) sie groß ist, (2) sie sich regelmäßig ändert und (3) sie stark von der Gruppe geschützt ist, die sie unterstützt.

Ich habe versucht:

xyzzy >&1 

zu versuchen, es zu überschreiben, aber der Ausgang noch nicht (möglicherweise, weil >&1 einen no-op betrachtet werden kann) nicht angezeigt.


Mit anderen Worten, da das Skript:

function xyzzy() { 
    echo hello 
} >/tmp/junk 

rm -f /tmp/junk 
echo ================ 
echo Standard output 
echo ---------------- 
xyzzy # something else here 
echo ================ 
echo Function capture 
echo ---------------- 
cat /tmp/junk 
echo ================ 

es derzeit gibt:

================ 
Standard output 
---------------- 
================ 
Function capture 
---------------- 
hello 
================ 

Was kann ich den xyzzy Aufruf ändern, um hello in den gedruckten zu erhalten Standard-Output-Abschnitt anstelle der Funktion Capture-Abschnitt?

Und das muss sein ohne versucht, die Datei zu lesen /tmp/junk, nachdem es seit den tatsächlichen Umleitungen erstellt wird zu /dev/null sein können, so werden sie nicht in einer Datei.

+0

Nicht nützlicher Kommentar: Ich habe 'xyzzy 1>/tmp/aaa' versucht und die Datei wird berührt, aber nicht mit Daten gefüllt. Es hat das gleiche Verhalten wie 'xyzzy 2>/tmp/aaa'. – fedorqui

+0

könnte es wert sein, dies auf http://unix.stackexchange.com zu fragen. – dogbane

+0

@dogbane, ich war daran zerrissen, da es sowohl Programmieren als auch Unix scheint. Ich wollte keinen Crosspost machen, aber wenn ich hier keine Antwort bekomme, kann ich es später noch einmal versuchen. – paxdiablo

Antwort

2

Das einzige, was mir einfällt, wäre, die Ausgabe von declare -f function_name zu analysieren und die Umleitung zu entfernen.

Dies ist vielleicht der einfachste Ansatz. Beachten Sie, dass Sie das Skript awk an das spezifische Funktionslayout anpassen müssen und dass es den Hauptteil der Funktion überhaupt nicht ändert. Das bedeutet, dass Sie die Umleitung nur auf der obersten Ebene deaktivieren können. Sie könnte ganze Anrufbäume von Funktionen ändern, um Umleitung zu deaktivieren, aber das würde einen bash Parser erfordern Erkennen und Ändern von Funktionsaufrufen innerhalb des Körpers.

Das folgende Skript zeigt, wie es mit Ihrer Beispielfunktion gemacht wird.Alle awk Befehl tut, ist eine neue Funktion my_xyzzy schaffen, spiegelt die xyzzy Funktion mit Ausnahme der letzten Zeile, die Effizienz in drehen:

function my_xyzzy() { 
    echo hello 
} 

und das komplette Skript als pro Spezifikationen:

function xyzzy() { 
    echo hello 
} >/tmp/qqqq 

declare -f xyzzy | awk ' 
    NR==1 {print "my_xyzzy()"} 
    NR==2 {prev=$0} 
    NR>2 {print prev;prev=$0} 
    END {print "}"}' >$$.bash 
. $$.bash 
rm -f $$.bash 

rm -f /tmp/qqqq 
echo ================ 
echo Standard output 
echo ---------------- 
my_xyzzy 
echo ================ 
echo Function capture 
echo ---------------- 
cat /tmp/qqqq 
echo ================ 

Die Ausgabe davon ist:

================ 
Standard output 
---------------- 
hello 
================ 
Function capture 
---------------- 
cat: /tmp/qqqq: No such file or directory 
================ 
+0

Ich habe tatsächlich etwas auf eine etwas andere Art und Weise gegeben, indem ich die eigentliche Skriptdatei mit den Funktionen darin durch einen Filter übergebe, der alle Funktionsdefinitionen ändert und zu etwas wie 'my_xyzzy' aufruft und dann _that._ Das ist mein Fallback-Position, wenn ich keine einfache Möglichkeit finde, die Umleitung zu überschreiben, da es einen ziemlich komplexen Parser benötigt, um alle Randfälle zu erfassen. – paxdiablo

+0

Glenn, ich fing an, meine eigene 'bash'-Variante zu entwickeln, die Funktionen nicht umleiten würde, wenn eine Variable gesetzt wurde (ich kann das Skript nicht ändern, aber es wurde mit einer leicht modifizierten 'bash' nicht abgezinst), aber es wurde auch hart. Also vermute ich, dass ich so gehen muss. Ich habe meine Ergebnisse zu Ihrer Antwort hinzugefügt, um sie etwas abzurunden. – paxdiablo

0

Ich glaube nicht, dass Bash Funktion Umleitungen überschrieben werden können dynamisch im Aufruf der Funktion selbst, obwohl ein temporär geänderter Shellkontext durch Kombination von Bash aliases und functions (siehe Magic Aliases: A Layering Loophole in the Bourne Shell) verwendet werden kann.

Nicht dynamisch ist es der letzte Umleitungsausdruck, d. e. der rechte, der die vorherigen überschreibt, wenn die Umleitungsausdrücke auf den gleichen Dateideskriptor verweisen.

# example 
ls -ld/no_such_file 1>/dev/null 1>/dev/tty 1>&2 1>redirtest.txt 
cat redirtest.txt 

Daher glenn jackman ‚s Vorschlag declare -f function_name zu verwenden scheint die Art und Weise einen endgültigen stdout Umleitung Ausdruck hinzufügen, um die vorherigen außer Kraft zu setzen.

xyzzy() { echo 'Hello, world!'; } 1>/dev/null 
#func="$(declare -f xyzzy) 1>&2" 
func="$(declare -f xyzzy) 1>/dev/tty" 
eval "$func" 
xyzzy 
Verwandte Themen