【问题标题】:Cannot redirect to a file descriptor stored in a variable无法重定向到存储在变量中的文件描述符
【发布时间】:2016-02-11 10:41:59
【问题描述】:

编者注:这个问题经过多次修改,改变了问题的性质,可能会使旧的 cmets 和答案无效;它的原始标题是“无法将 Bash 输出重定向到 /dev/null”。

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

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

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

然后在我的脚本中:

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

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

这是由于我重定向的顺序还是我的变量错误?编辑:脚本现在可以完全正常工作了,将"&1" 替换为"/dev/tty" 作为输出值。

【问题讨论】:

  • 在此处发布之前尝试shellcheck.net。提名关闭为简单的错字。
  • 感谢您的链接!但是,即使在修正了错字之后,也存在一个问题:详细模式是打开还是关闭,输出总是一样的。
  • @Lupuss 也重定向标准错误
  • 您可以使用exec > /dev/null 2>&1 永久重定向stdout 和stderr。

标签: bash verbosity


【解决方案1】:

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

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

【讨论】:

  • 现在当我处于“静默”模式而不是详细模式时它可以正常工作:)
  • 后见之明(不幸的是,OP 多次更改了问题):虽然这个答案显示了一种普遍有用的技术 - 如何将 stderr 输出发送到发送 stdout 输出的同一目标(重定向) 到 - 它没有解决 OP 的最终版本问题,该问题源于尝试将重定向存储到 variable 中的文件 descriptor,这是不受支持的. Quibble:2>&1 不重定向 stderr before 重定向 stdout;相反,它将 stderr 重定向到 already-redirected 标准输出,即 在 标准输出被重定向之后。
【解决方案2】:

tl;dr

  • 您不能在变量中存储对文件描述符(在您的情况下为&1)的重定向-如果这样做,您将创建一个file 改用该名称(在您的情况下,文件字面名称为 &1)。

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

  • 从 cmets 获取 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.

为了解决您的问题,我建议从 cmets 获取 gniourf_gniourf's 建议:改用 exec:

#!/usr/bin/env bash

if [[ $1 == '-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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-26
    • 2015-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 2018-10-05
    相关资源
    最近更新 更多