我有两个BASH脚本,它们启动我通常使用的程序,这些程序带有公共参数,使用命令和参数的变量。调用显示在末尾,如下所示:
$PROGRAM $ARG1 $ARG2 &
现在,我想在默认情况下将输出重定向到stderr,并将stdout重定向到/dev/null
。我希望能够通过切换到脚本来禁用它(-v
=verbose)。但是,如果我尝试将"2>&1 > /dev/null"
分配给一个var,比如REDIRECTION
(如果指定了verbose,则清除它),并尝试调用如下:
$PROGRAM $ARG1 $ARG2 $REDIRECTION &
重定向指令作为参数传递给程序。有办法做到这一点吗?或者,我必须使用我的解决方案,即有两个独立的调用行,一个带有重定向指令,另一个没有重定向指令,这取决于"详细程度"?
一个选项是使用eval
内置函数,它像Bash命令一样处理参数,处理重定向运算符之类的事情。然而,eval
是非常危险的,因为它会重新处理所有的参数,即使是已经正确处理的参数,如果不完美地,这可能会导致奇怪或不安全的行为。
由于两个版本的命令之间唯一有问题的区别是是否存在重定向,因此更好的选择是使用exec
内置。此命令:
exec >/dev/null 2>&1
将shell脚本的剩余部分的STDOUT和STDERR重定向到/dev/null
。此命令:
[[ "$IS_VERBOSE" ]] || exec >/dev/null 2>&1
将运行exec >/dev/null 2>&1
,除非$IS_VERBOSE
为非空,在这种情况下它什么也不做。(您可以将[[ "$IS_VERBOSE" ]]
替换为您已经用于检测详细程度的任何类型的条件表达式。)
所以,你想要的是这样的东西:
(
[[ "$IS_VERBOSE" ]] || exec >/dev/null 2>&1
"$PROGRAM" "$ARG1" "$ARG2" &
)
括号中的( ... )
用于设置子shell,因此exec
命令(如果运行)只影响到)
。
(顺便说一句,注意我把你的2>&1 > /dev/null
改成了> /dev/null 2>&1
:订单很重要。)
与其尝试将shell语法编码到参数中,不如将每个重定向运算符的默认目的地放在参数中,并允许一个方法来覆盖默认目的地。
# A little bash-specific, but appropriate defaults should exist for the shell
# of your choice.
STDOUT=/dev/stdout
STDERR=/dev/stderr
if some-test; then
STDOUT=some-other-file
fi
if some-other-test; then
STDERR=different-file
fi
$PROGRAM $ARG1 $ARG2 > $STDOUT 2> $STDERR
您可以构建任何您喜欢的命令行,然后使用eval执行它:
line="echo hello"
if ....
line="$line > junk.out"
fi
eval $line
(但我可能会选择你建议的更容易阅读和理解的2行方法…)