bash:使用变量来存储 stderr|stdout 重定向

bash:使用变量来存储 stderr|stdout 重定向

有没有办法通过变量重定向 stdout 和 stderr,例如在脚本中添加命令选项?

例如我有一个脚本:

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
mkdir $OPT 123/123/123 $TEST

我可以看到 OPT 被替换为-p没有任何问题,并且 bash 将其解释为选项。但重定向解释为目录名称。

$ ./test.sh 
+ TEST='>/dev/null 2>&1'
+ OPT='-p -v'
+ mkdir -p -v 123/123/123 '>/dev/null' '2>&1'
mkdir: created directory `123/123'
mkdir: created directory `123/123/123'
mkdir: created directory `>/dev'
mkdir: created directory `>/dev/null'
mkdir: created directory `2>&1'

有没有办法说 bash,$VAR 是重定向,而不是目录名称。

附言。可能我走错了路,但我想从我的脚本中进行可选的详细或非详细输出。但即使在非详细模式下,我也需要一些输出,因此我不能仅从脚本内的某些命令重定向整个 stdout 和 stderr。

答案1

另一种解决方案可能如下:

#!/bin/bash

verbose=0

exec 3>&1
exec 4>&2

if ((verbose)); then
  echo "verbose=1"
else
  echo "verbose=0"
  exec 1>/dev/null
  exec 2>/dev/null
fi

echo "this should be seen if verbose"
echo "this should always be seen" 1>&3 2>&4

然后1>&3 2>&4仅添加到您想要查看输出的命令。

答案2

“如何”在其他答案中已经得到很好的解释;我想解决OP代码不起作用的“原因”。

基调是输出重定向已标记变量扩展。 重定向实际上是执行的变量扩展后(因此您可以将输出重定向到存储在变量中的文件名),但是 shell识别在变量扩展之前进行后续处理的重定向。

换句话说,一旦变量被扩展,考虑重定向字符(<>等)就“太晚了”,因为 shell 已经识别出它将作为重定向处理命令字符串的哪些部分。

如需进一步阅读,请参阅下面列出的步骤 1 和 3:

LESS='+/^SIMPLE COMMAND EXPANSION' man bash

答案3

它不会将其解释为“目录名称”,>而是被引用,因此它被按字面意思处理(更具体地说,您正在发送字符串>dev/null 2>&1。解决此问题的唯一方法是使用eval或生成一个新的 shell。

至于你的问题中提到的“详细”问题,只需这样做:

verbose=1
if (( verbose )); then
    mkdir -v -p /foo
else
    mkdir -p /foo > /dev/null 2>&1
fi

答案4

您的变量中有很多空格,这些空格将无法正确评估。您将需要使用eval它来进行设置。

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
eval mkdir $OPT 123/123/123 $TEST

这将允许 $OPT 被拆分为两个参数(-p-v),而不是一个(-p -v),并且与 $TEST 相同。也更改为使用,因为当前目录中/dev/null不太可能有目录。dev

相关内容