无法重定向到存储在变量中的文件描述符

Cannot redirect to a file descriptor stored in a variable

编者注:这个问题经过多次修改,改变了问题的性质,可能会使旧的评论和答案无效;它的原始标题是 "Cannot redirect Bash output to /dev/null".

我正在尝试创建一个小的 Bash 脚本,我想为其实现静默模式。基本上我只想默认隐藏大部分输出,如果我用 -v 运行 显示所有输出。

所以在我的脚本开头我放了:

#!/bin/bash
declare output=''
if [ "" = -v ]; then
  output="&1"
else
  output="/dev/null"
fi

然后在我的脚本中我有:

{
  # whatever commands...
} > $output 2>&1

静音模式效果很好。但是,如果我尝试详细模式,则会创建一个名为 &&1 的文件(基于我的 output 变量)。另外,文件是空的。这不是期望的结果:我希望输出保留在终端上!

这是因为我重定向的顺序还是我的变量错了?编辑:通过将 "&1" 替换为 "/dev/tty".

作为输出值,脚本现在可以完全运行

很可能正在打印错误输出。请注意,使用 > /dev/null 时,只会重定向 stdout 而不会重定向 stderr。在重定向 stdout 之前,您可以使用 2>&1 将 stderr 重定向到 stdout。类似于:

{
  # whatever commands...
} > $output 2>&1

tl;dr

  • 您不能在变量[=58=中存储指向文件描述符&1) ] - 如果你这样做,你将创建一个 file 来代替(在你的情况下,一个字面上名为 &1 的文件)。

  • 设置 $output/dev/tty 是不明智的,因为你 always 输出到终端,这会阻止捕获文件中的详细输出;例如,script -v > file 将不起作用。

  • 从评论中获取 gniourf_gniourf's 建议,并使用 exec 代替:exec > /dev/null 2>&1 或使用 Bash 特定语法,exec &>/dev/null 使脚本的其余部分静音。


重定向到文件描述符只有效:

  • 如果重定向目标是文字,而不是变量引用。
  • 如果 > 和目标之间没有空格
date > &1 # !! SYNTAX ERROR: syntax error near unexpected token `&'

date >&1  # OK - but works with a *literal* `&1` only

如果你使用变量,那没关系,因为变量内容总是被解释为文件名 - 这就是为什么您没有遇到语法错误,但最终得到了一个字面上名为 &1 的输出文件。

output='&1'
date >$output  #  !! Creates a *file* named '&1'.
date > $output #  !! Ditto.

为了解决您的问题,我建议采纳评论中的 gniourf_gniourf's 建议:改用 exec

#!/usr/bin/env bash

if [[  == '-v' ]]; then
  : # verbose mode: redirect nothing
else 
  # quiet mode: silence both stdout and stderr
  exec &>/dev/null
fi

echo 'hello'      # will only print with -v specified
echo 'hello' >&2  # ditto