如何将重定向符号分配给变量以组装命令行

4

我有一些BASH脚本,用于启动我常用的程序,并使用变量来表示命令和参数。调用方式如下:

$PROGRAM $ARG1 $ARG2 &

现在我想默认将输出重定向到stderr和stdout到/dev/null。 我希望能够通过脚本中的开关(-v=详细模式)禁用它。但是,如果我尝试将"2>&1 > /dev/null"分配给一个变量,比如REDIRECTION(如果指定了详细模式,则清除它),并尝试这样调用:
$PROGRAM $ARG1 $ARG2 $REDIRECTION &

重定向指令作为参数传递给程序。有没有一种方法可以做到这一点?或者我必须使用我的解决方案,根据“详细程度”分别使用两个不同的调用行,一个带有重定向指令,一个没有?
3个回答

5

一种选择是使用内置的eval,它处理其参数就像Bash命令一样,处理诸如重定向运算符之类的内容。然而,eval相当危险,因为它将重新处理所有的参数,甚至那些已经被正确处理的参数,如果不做到完美,这可能会导致奇怪或不安全的行为。

由于你的命令的两个版本之间唯一的问题是是否存在重定向,更好的选择是使用内置的exec。这个命令:

exec >/dev/null 2>&1

将脚本剩余部分的 STDOUT 和 STDERR 重定向到/dev/null。这个命令:

[[ "$IS_VERBOSE" ]] || exec >/dev/null 2>&1

如果$IS_VERBOSE为空,则运行 exec >/dev/null 2>&1,否则不执行任何操作。 (您可以使用已经用于检测详细信息的任何条件表达式替换[[ "$IS_VERBOSE" ]]。)

所以,您需要这样的内容:

(
    [[ "$IS_VERBOSE" ]] || exec >/dev/null 2>&1
    "$PROGRAM" "$ARG1" "$ARG2" &
)

括号( ... )用于设置子shell,因此exec命令(如果运行)只会影响到括号前的部分。

(顺便提一下,注意我将你的2>&1 > /dev/null更改为> /dev/null 2>&1:顺序很重要。)


那么,括号 ( ... ) 内执行的任何程序都会受到 exec 命令的影响? - Yamaneko
@VictorHugo:是的。(更准确地说:exec 命令会影响 shell 本身。就好像你只是将 Bash 脚本剩余部分重定向到 ) 一样。由于该脚本内部的命令从它继承其 STDIN 和 STDOUT,因此它们都会受到影响。) - ruakh

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

0
你可以构建任何命令行,然后使用 eval 执行它:
line="echo hello"
if ....
    line="$line > junk.out"
fi

eval $line

(但我可能会选择你建议的两行方法,因为它更容易阅读和理解...)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接