7 shell bash io-redirection background-process
几周前,我看到了一个关于“ (如何)在后台静默启动任务? ”这个问题的奇怪答案。这个解决方案似乎不正确(参见我的回答),尽管 shell 似乎在后台默默地启动了任务。
建议的解决方案没有任何解释,分析也没有提供可靠的答案。
在下面,您可以看到代码片段。
# Run the command given by "$@" in the background
silent_background() {
if [[ -n $BASH_VERSION ]]; then
{ 2>&3 "$@"& } 3>&2 2>/dev/null
fi
}
Run Code Online (Sandbox Code Playgroud)
有问题的命令是{ 2>&3 "$@"& } 3>&2 2>/dev/null.
命令组{ ... }( ) 为一个命令 ( )指定了两个重定向 (3>&2和)。该命令是一个具有一个重定向 ( )的异步列表( )。2>/dev/null# Run the command given by "$@" in the backgroundcmd&2>&3
POSIX 规范
每个重定向应适用于复合命令中所有未明确覆盖该重定向的命令。
标准错误重定向2>/dev/null被与异步列表关联的重定向覆盖2>&3。
在第一种情况下,标准错误被重定向到,/dev/null而在第二种情况下,命令的标准错误仍然附加到终端。
prompt% { grep warning system.log& } 2>/dev/null
prompt% { 2>&3 grep warning system.log& } 3>&2 2>/dev/null
grep: system.log: No such file or directory
Run Code Online (Sandbox Code Playgroud)
下面,我们可以看到类似的案例。在第一种情况下,命令的标准输出仍然附加到终端。在第二种情况下,命令的标准输出重定向被修改:>echo.txt被>print.txt.
prompt% { >&3 echo some data...& } 3>&1 >echo.txt
[1] 3842
some data...
prompt% file echo.txt
echo.txt: empty
prompt% { >&3 echo some data...& } 3>print.txt >echo.txt
[1] 2765
prompt% file echo.txt
echo.txt: empty
prompt% cat print.txt
some data...
Run Code Online (Sandbox Code Playgroud)
如前所述,该命令似乎在后台静默启动。更准确地说,[1] 3842不显示有关后台作业的通知,例如。
前面的分析意味着重定向是多余的,因为它们可能会被取消。
{ redir_3 cmd& } redir_1 redir_2相当于cmd&。
在我看来,上述构造由于副作用而隐藏了通知。
你能解释一下这是怎么发生的吗?
Ilkkachu 的回答和评论允许一些进展。请注意,每个进程都有自己的文件描述符。
另一个上下文:在子 shell 中执行的异步列表。该命令g不存在。
prompt% ( g& )
g: command not found
Run Code Online (Sandbox Code Playgroud)
异步命令,用括号分组的命令,...,在与 shell 环境重复的子 shell 环境中执行...
子外壳从其父外壳继承其标准错误流的值。
因此,在前一种情况下,它们的标准错误流应该是指终端。但是,不会显示作业通知,而外壳错误消息可能会显示在外壳标准错误上。
您错过了最重要的一点,shell 重定向是按从左到右的顺序应用的。
在:
{ 2>&3 "$@"& } 3>&2 2>/dev/null
Run Code Online (Sandbox Code Playgroud)
整个组命令运行:
所以当分组内的命令运行时:
因此,如果将"$@"&任何内容打印到其标准错误,则输出将打印到终端。
对于您的具体案例:
{ grep warning system.log& } 2>/dev/null
Run Code Online (Sandbox Code Playgroud)
{ grep warning system.log& }运行时标准错误指向/dev/null. grep不会覆盖任何重定向,因此其标准错误与 相同{...},并重定向到/dev/null,您没有输出到终端。
在:
{ 2>&3 grep warning system.log& } 3>&2 2>/dev/null
Run Code Online (Sandbox Code Playgroud)
grep的标准错误被重定向到文件描述符 3,它如上所述指向终端,因此您将输出到终端。