如何在bash中有条件地抑制重定向?
我有一个名为“run”的shell函数,它通常只将其参数视为命令行(即,好像没有使用“run()”)。但是,如果脚本在如何在bash中有条件地抑制重定向?,bash,io-redirection,Bash,Io Redirection,我有一个名为“run”的shell函数,它通常只将其参数视为命令行(即,好像没有使用“run()”)。但是,如果脚本在$TESTMODE中运行,“run()”将回显其参数,而不是: run () { cmd="$@" if [ -z "$TESTMODE" ]; then $cmd else echo "### RUN: '$cmd'" fi } 其思想是,命令runrm-Rf/通常会尝试删除整个根文件系统。但是,如果定义了$TESTMODE,那么它将响应 ##
$TESTMODE
中运行,“run()”将回显其参数,而不是:
run ()
{
cmd="$@"
if [ -z "$TESTMODE" ]; then
$cmd
else
echo "### RUN: '$cmd'"
fi
}
其思想是,命令runrm-Rf/
通常会尝试删除整个根文件系统。但是,如果定义了$TESTMODE,那么它将响应
### RUN: rm -Rf /
在您尝试在包含重定向的命令行上使用run()之前,它工作得非常好:
run which which
run which bash >quiet
在这种情况下,当定义了$TESTMODE
时,人眼将永远看不到所需的回波
:
$ rm quiet
$ TESTMODE=yes ./runtest.sh
### RUN: 'which which'
$ cat quiet
### RUN: 'which bash'
我尝试使用字符串替换来更正此问题:
run ()
{
cmd="$@"
if [ -z "$TESTMODE" ]; then
$cmd
else
cmd=${cmd//\>/\\>}
cmd=${cmd//\</\\<}
echo "### RUN: '$cmd'"
fi
}
。。。但是在我的bash脚本中失败得很惨(行为没有明显的变化)
帮忙?我肯定这与引用有关,但我不确定具体如何解决
运行哪个bash>quiet
这会使标准输出静音,但不会使标准输出静音
所以你可以试试这个
echo“###RUN:'$cmd'>/dev/stderr
或者干脆
echo "### RUN: '$cmd'" >&2
运行哪个bash>quiet
这会使标准输出静音,但不会使标准输出静音
所以你可以试试这个
echo“###RUN:'$cmd'>/dev/stderr
或者干脆
echo "### RUN: '$cmd'" >&2
这不是逃避的问题;重定向发生在函数启动之前,超出了函数的控制范围。例如,当bash看到命令
runwhichbash>quiet
,bash首先将输出重定向到文件“quiet”,然后执行参数为“which”和“bash”的“run”函数。函数发送到stdout的任何内容都会自然地进入文件“quiet”
你的脚本还有另一个问题。将命令存储在变量(cmd=“$@”
)中时,会松开参数之间的分隔符。例如,您无法判断命令是运行touch“foo bar”
还是运行touch“foo”“bar”
——在这两种情况下,$cmd都设置为“touch foo bar”。这对于打印命令来说可能没问题,但由于您是以这种形式执行它,因此可能会造成麻烦。要解决此问题,请避免将其存储在变量中,或将其存储为数组(cmd=(“$@”)
;然后将其作为“${cmd[@]}”
执行
有几种方法可以解决输出重定向问题。您可以将输出发送到stderr而不是stdout:
run ()
{
if [ -z "$TESTMODE" ]; then
"$@"
else
echo "### RUN: '$*'" >&2
fi
}
…但这有几个问题:它仍然执行重定向而不是打印它(runwhichbash>quiet
将创建一个名为“quiet”的空文件,然后打印“###run:‘which bash’”
此外,如果stderr已被重定向,它将打印到该服务器而不是终端。这可能是好的,也可能是坏的,这取决于你的意图。另一种可能是使用echo“####RUN:'$*'”>/dev/tty
直接发送到终端。这里可能存在的问题:如果没有tty(例如,在cron作业中),它将失败
最后一点注意:在echo
命令中,我使用了$*
而不是$@
,因为我希望整个命令被视为一个带空格的字符串,而不是一系列字符串。这使得打印输出不明确(例如,运行touch“foo bar”
与运行touch“foo”“bar”
——两者都会打印###run:'touch foo bar'
),但这远不如正确执行命令重要。如果您想要明确的日志记录,则必须执行以下更复杂的操作:
echo "### RUN:" >&2
printf " %q" "$@" >&2
echo >&2
printf的
%q
格式将为命令及其参数使用明确的(和shell可执行的)格式。这不是转义的问题;重定向发生在函数启动之前,超出了函数的控制范围。例如,当bash看到命令runwhichbash>quiet
,bash首先将输出重定向到文件“quiet”,然后执行参数为“which”和“bash”的“run”函数。函数发送到stdout的任何内容都会自然地进入文件“quiet”
你的脚本还有另一个问题。将命令存储在变量(cmd=“$@”
)中时,会松开参数之间的分隔符。例如,您无法判断命令是运行touch“foo bar”
还是运行touch“foo”“bar”
——在这两种情况下,$cmd都设置为“touch foo bar”。这对于打印命令来说可能没问题,但由于您是以这种形式执行它,因此可能会造成麻烦。要解决此问题,请避免将其存储在变量中,或将其存储为数组(cmd=(“$@”)
;然后将其作为“${cmd[@]}”
执行
有几种方法可以解决输出重定向问题。您可以将输出发送到stderr而不是stdout:
run ()
{
if [ -z "$TESTMODE" ]; then
"$@"
else
echo "### RUN: '$*'" >&2
fi
}
…但这有几个问题:它仍然执行重定向而不是打印它(runwhichbash>quiet
将创建一个名为“quiet”的空文件,然后打印“###run:‘which bash’”
此外,如果stderr已被重定向,它将打印到该服务器而不是终端。这可能是好的,也可能是坏的,这取决于你的意图。另一种可能是使用echo“####RUN:'$*'”>/dev/tty
直接发送到终端。这里可能存在的问题:如果没有tty(例如,在cron作业中),它将失败
最后一点注意:在echo
命令中,我使用了$*
而不是$@
,因为我希望整个命令被视为一个带空格的字符串,而不是一系列字符串。这使得打印输出不明确(例如,运行touch“foo bar”
与运行touch“foo”“bar”
——两者都会打印###run:'touch foo bar'
),但这远不如正确执行命令重要。如果您想要明确的日志记录,则必须执行以下更复杂的操作:
echo "### RUN:" >&2
printf " %q" "$@" >&2
echo >&2
printf的%q
格式将使用一种明确的(和shell可执行的)c语言格式