1

我有一个名为“run”的shell函数,通常只是将其参数视为命令行(即,好像没有使用'run()'。)但是,如果脚本在a中运行$TESTMODE,则'run() ' 将回显其参数,而不是:

run ()
{
  cmd="$@"
  if [ -z "$TESTMODE" ]; then
    $cmd
  else
    echo "### RUN: '$cmd'"
  fi
}

这个想法是,该命令run rm -Rf /通常会尝试删除整个根文件系统。但是,如果定义了 $TESTMODE,那么它会回显

### RUN: rm -Rf /

它工作得很好,直到您尝试在包含重定向的命令行上使用 run() :

run which which
run which bash >quiet

在这种情况下,当$TESTMODE定义时,echo人眼将永远无法看到所需的内容:

$ 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
}

...在命令行测试中似乎很有希望:

$ test1="foo >bar"
$ echo $test1
foo >bar
$ test2=${test1//\>/\\>}
$ echo $test2
foo \>bar

...但在我的 bash 脚本中惨遭失败(行为没有明显变化)。

帮助?我确信这与引用有关,但我不确定如何解决它。

4

2 回答 2

2

运行 which bash >quiet

这会使 STDOUT 的输出静音,但不会静音 STDERR

所以你可以试试这个

echo "### RUN: '$cmd'" >/dev/stderr

或者干脆

echo "### RUN: '$cmd'" >&2

参考

于 2013-01-16T03:51:41.787 回答
2

这不是逃避的问题;重定向发生在您的函数甚至开始之前,并且不在函数的控制范围内。例如,当 bash 看到 command 时run which bash >quiet,bash 首先将输出重定向到文件“quiet”,然后执行带有参数“which”和“bash”的“run”函数。您的函数发送到标准输出的任何内容都会自然地进入“安静”文件。

您的脚本还有另一个问题。当您将命令存储在变量 ( cmd="$@") 中时,它会丢失参数之间的中断。例如,您无法判断该命令是run touch "foo bar"还是run touch "foo" "bar"-- 在任何一种情况下,$cmd 都设置为“touch foo bar”。这对于打印命令可能没问题,但是由于您以这种形式执行它,因此可能会引起麻烦。要解决此问题,请避免将其存储在变量中,或者将其存储为数组(cmd=("$@"); 然后将其执行为"${cmd[@]}")。

有几种方法可以解决输出重定向问题。您可以将输出发送到 stderr 而不是 stdout:

run ()
{
  if [ -z "$TESTMODE" ]; then
    "$@"
  else
    echo "### RUN: '$*'" >&2
  fi
}

...但这有一些问题:它仍然执行重定向而不是打印它(run which bash >quiet将创建一个名为“quiet”的空文件,然后打印“### RUN: 'which bash'”)。

此外,如果 stderr 已被重定向,它将打印到那个而不是终端。这可能是好是坏,取决于您的意图。另一种可能性是直接发送到终端echo "### RUN: '$*'" >/dev/tty。这里可能存在的问题:如果没有 tty(例如在 cron 作业中),它将失败。

最后说明:在echo命令中,我使用$*了代替,$@因为我希望将整个命令视为带有空格而不是一系列字符串的单个字符串。这使得打印输出模棱两可(例如run touch "foo bar"run touch "foo" "bar"-- 两者都会 print ### RUN: 'touch foo bar'),但这并不像正确执行命令那么重要。如果你想要明确的日志记录,你必须做一些更复杂的事情,比如:

echo "### RUN:" >&2
printf " %q" "$@" >&2
echo >&2

printf 的%q格式将为命令及其参数使用明确的(和 shell 可执行的)格式。

于 2013-01-16T04:06:03.873 回答