Reputation: 882186
I recently discovered some bash
code that used the little-known (well, little known to me anyway) feature of function redirection, such as the greatly simplified:
function xyzzy () {
echo hello
} >/dev/null
When you call the function with a simple xyzzy
, it automatically applies the redirections attached to the function regardless of what you've done when calling it.
What I'd like to know is if there's any way to override this behaviour in the call to the function itself, to see the message being generated. I'm reticent to change the file containing all the functions since (1) it's large, (2) it changes regularly, and (3) it's heavily protected by the group that supports it.
I've tried:
xyzzy >&1
to try to override it but the output still doesn't show up (possibly because >&1
may be considered a no-op).
In other words, given the script:
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 ================
it currently outputs:
================
Standard output
----------------
================
Function capture
----------------
hello
================
What can I change the xyzzy
call to, so as to get hello
printed in the standard output section rather than the function capture section?
And this needs to be without trying to read the file /tmp/junk
after it's created since the actual redirections may be to /dev/null
so they won't be in a file.
Upvotes: 9
Views: 2185
Reputation: 247042
The only thing I can think of would be to parse the output of declare -f function_name
and remove the redirection.
This is perhaps the easiest approach. Note that you need to tailor the awk
script to the specific function layout and it doesn't modify the body of the function at all. That means you can only turn off redirection at the top level. You could modify whole call trees of functions to turn off redirection but that would require a bash
parser capable of recognising and changing function calls within the body.
The following script shows how to do it with your sample function. All the awk
command does is create a new function my_xyzzy
which mirrors the xyzzy
function except for the final line, effectively turning it into:
function my_xyzzy () {
echo hello
}
And the complete script as per the specifications:
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 ================
The output of that is:
================
Standard output
----------------
hello
================
Function capture
----------------
cat: /tmp/qqqq: No such file or directory
================
Upvotes: 2
Reputation: 1
I don't think Bash function redirections can be overridden dynamically in the call to the function itself although a temporarily altered shell context can be made use of by combining Bash aliases
and functions
(see Magic Aliases: A Layering Loophole in the Bourne Shell).
Non-dynamically it is the last redirection expression, i. e. the rightmost one, that overrides the previous ones if the redirection expressions refer to the same file descriptor.
# example
ls -ld / no_such_file 1>/dev/null 1>/dev/tty 1>&2 1>redirtest.txt
cat redirtest.txt
Therefore, glenn jackman's suggestion to use declare -f function_name
seems the way to add a final stdout
redirection expression to override the previous ones.
xyzzy() { echo 'Hello, world!'; } 1>/dev/null
#func="$(declare -f xyzzy) 1>&2"
func="$(declare -f xyzzy) 1>/dev/tty"
eval "$func"
xyzzy
Upvotes: 0