无法重定向到存储在变量中的文件描述符
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
编者注:这个问题经过多次修改,改变了问题的性质,可能会使旧的评论和答案无效;它的原始标题是 "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