8

我最近发现了一些bash代码使用了函数重定向的鲜为人知(好吧,无论如何都不知道)特性,例如大大简化的:

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

当您使用 simple 调用该函数时xyzzy,它会自动应用附加到该函数的重定向,而不管您在调用它时做了什么。

我想知道的是是否有任何方法可以在对函数本身的调用中覆盖此行为,以查看正在生成的消息。我不愿更改包含所有功能的文件,因为 (1) 它很大,(2) 它定期更改,以及 (3) 它受到支持它的组织的严格保护。

我试过了:

xyzzy >&1

尝试覆盖它,但输出仍然没有显示(可能是因为>&1可能被认为是无操作)。


换句话说,给定脚本:

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 ================

它目前输出:

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

我可以将xyzzy调用更改为什么,以便hello在标准输出部分而不是函数捕获部分打印?

并且这需要在创建文件后尝试读取文件/tmp/junk,因为实际的重定向可能是,/dev/null因此它们不会文件中。

4

2 回答 2

2

我能想到的唯一想法是解析输出declare -f function_name并删除重定向。

这可能是最简单的方法。请注意,您需要根据awk特定的函数布局定制脚本,并且它根本不会修改函数的主体。这意味着您只能在顶层关闭重定向。您可以修改整个函数调用树以关闭重定向,但这需要bash解析器能够识别和更改主体内的函数调用。

以下脚本显示了如何使用示例函数执行此操作。该awk命令所做的只是创建一个新函数my_xyzzy,该xyzzy函数反映除最后一行之外的函数,有效地将其转换为:

function my_xyzzy () {
    echo hello
}

以及按照规范的完整脚本:

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 ================

它的输出是:

================
Standard output
----------------
hello
================
Function capture
----------------
cat: /tmp/qqqq: No such file or directory
================
于 2013-07-29T10:02:45.930 回答
0

我不认为 Bash 函数重定向可以在对函数本身的调用中被动态覆盖,尽管可以通过组合 Bashaliases和来使用临时更改的 shell 上下文functions(参见Magic Aliases: A Layering Loophole in the Bourne Shell)。

如果重定向表达式引用相同的文件描述符,它是最后一个重定向表达式,即最右边的重定向表达式,它会覆盖先前的重定向表达式。

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

因此,glenn jackman的使用建议declare -f function_name似乎是添加最终stdout重定向表达式以覆盖先前表达式的方式。

xyzzy() { echo 'Hello, world!'; } 1>/dev/null
#func="$(declare -f xyzzy) 1>&2"
func="$(declare -f xyzzy) 1>/dev/tty"
eval "$func"
xyzzy
于 2013-07-29T16:12:23.843 回答