![exec内置外壳(第一个细微差别)](https://linux22.com/image/1114597/exec%E5%86%85%E7%BD%AE%E5%A4%96%E5%A3%B3%EF%BC%88%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%BB%86%E5%BE%AE%E5%B7%AE%E5%88%AB%EF%BC%89.png)
我试图将程序(Steam)的所有输出重定向到 /dev/null,这样它就不会出现在终端中。
这是我尝试过的
steam & > /dev/null 2>/dev/null
:steam & > /dev/null 2>&1
据我所知,两者都不会抑制其信息。
我的理解是 & 将进程与终端分离,而 > 重定向输入/输出,默认/空白 > 为 stdout,2> 为 stderr。除了这两个之外,还有更多的输出吗?如果我将所有内容重定向,为什么仍然可以看到输出?
答案1
尝试:
steam 2>&1 > /dev/null &
2>&1
将 stderr 重定向到 stdout,并将> /dev/null
stdout 重定向到/dev/null
。
进程&
到后台的 放错了位置。它必须放在行尾。如果放在 之后steam
但在 之前>
,则steam
不会重定向任何来自 的内容,尽管进程将正确地进入后台。
答案2
这个特定问题恰好steam
是一个特殊情况,有时可能需要一些特殊的理解和处理。steam
运行时是一个包装器脚本,包含以下内容:
#!/bin/bash
# default to minimize on close, so we never have a running steam process
# in the background because of a broken Tray Icon on some desktops/WMs
#export STEAM_FRAME_FORCE_CLOSE=${STEAM_FRAME_FORCE_CLOSE:-0}
exec /usr/lib/steam/steam "$@"
请注意,它使用exec
内置的 shell,以及传递所有参数$@
。
因此,虽然 shell 输出重定向的常用解决方案类似于@Adobe 和 @Gary 的回答,这种特殊情况通常需要更细致的方法和对幕后情况的理解。有些微妙之处导致所有可能的输出重定向方法和操作顺序steam
有时无法按预期工作。
exec
内置外壳(第一个细微差别)
POSIX 标准定义了命令exec
。Bash 通过exec
Shell 内置. 这可能会影响标准 IO 重定向和子进程树,具体取决于如何调用它。 笔记:虽然这在技术上并不适用于 OP 的特定用例和列出的命令,但我将其包括在这里,因为它是一个需要注意的常见陷阱和警告。
摘自 IEEE Std. 1003.1,2004 版:
exec 实用程序将根据命令中任何重定向的指定打开、关闭和/或复制文件描述符。
如果指定 exec 时不带命令或参数,并且使用关联的重定向语句打开任何编号大于 2 的文件描述符,则无法确定当 shell 调用另一个实用程序时这些文件描述符是否保持打开状态。担心子 shell 可能滥用打开的文件描述符的脚本始终可以显式关闭它们,如以下示例之一所示。
如果 exec 指定了命令,它将用命令替换 shell,而不创建新进程。如果指定了参数,它们将是命令的参数。重定向会影响当前 shell 执行环境。
exec /usr/lib/steam/steam "$@"
包装脚本中的行将替换/usr/bin/steam
正在执行的/bin/bash
shell(按照“shebang 行”),而不创建新的子进程。参数$@
说明符用双引号传递,在大多数情况下可以避免 IO 重定向运算符的任何副作用。但是,请注意,将某些输出重定向运算符作为参数传递(例如通过错误的引号"
或'
通过eval
转义字符\
)可能会有机会将 shell 重定向运算符注入脚本,从而调用exec
可能会影响命令的标准 IO 和文件描述符。因此,根据您向包装脚本传递或其他重定向运算符的方式,它们将在以下上下文中进行评估:2>&1
。幸运的是,在这种情况下双引号可以消除大多数副作用,但重要的是要注意哪个 bash 进程或子 shell 正在评估这些参数。>somefile
"$@"
Unix 输出重定向:stdin
,,stdout
&stderr
大多数 Unix重新编译shell 有类似的方法来重定向标准输入输出流、、、和。这包括但不限于:POSIX 、Bash、Z Shell stdin
、Korn Shell 、C Shell 、Dash等。stdout
stderr
sh
zsh
ksh
csh
dash
就 OP 的问题而言,我们只关注 Bash,因为/usr/bin/steam
包装器脚本以 Bash “舍邦“ 线:#!/bin/bash
。
在 Bash 中,前 3 个文件描述符(fd
)始终定义如下,索引从零开始0
:
stdin
=fd 0
stdout
=fd 1
stderr
=fd 2
任何命令的输出都可以使用Bash 中的输出重定向运算符(Bash 参考手册:§ 3.6 重定向)关于这个的基本介绍可以参看这篇文章:使用描述符实现 Bash 重定向。为了更直观的解释,借助视觉辅助,请参阅这篇精彩文章(强烈推荐!)。
运算顺序(第二个细微差别):
以下之间存在着微妙的操作顺序:
- 重定向运算符(
>
,<
,>>
,<<
,&>
,&>>
,X<&Y
,X>&Y
,X>|Y
,X<&Y-
,X<>Y
, ETC...)
...以及:
- 控制运算符(
&
,,/ ,,,,,,,,)。;
\n
newline
||
&&
;;
;&
;;&
|
|&
(
)
重定向按照其出现的顺序从左到右进行处理。
[...剪切...]
请注意,重定向的顺序很重要。例如,命令
ls > dirlist 2>&1
将标准输出(文件描述符 1)和标准错误(文件描述符 2)定向到文件 dirlist,而命令
ls 2>&1 > dirlist
仅将标准输出定向到文件 dirlist,因为在将标准输出重定向到 dirlist 之前,标准错误已成为标准输出的副本。
&
类似地,和其他控制运算符也有一定的运算顺序。
列表是由操作符“
;
”、“&
”、“&&
”或“ ”之一分隔的一个或多个管道序列,并且可以选择以“ ”、“ ”或“ ”||
之一终止。;
&
newline
在这些列表运算符中,'
&&
' 和 '||
' 具有相同的优先级,其次是 ';
' 和 '&
',它们具有相同的优先级。可以出现一个或多个换行符序列来
list
分隔命令,相当于分号。
最后,具体来说关于以下内容的部分&
:
如果命令以控制操作符“
&
”结束,则 shell 将在子 shell 中异步执行该命令。这称为在背景,这些被称为异步命令。shell 不会等待命令完成,返回状态为0
(true
)。当作业控制未处于活动状态时(请参阅作业控制),在没有任何显式重定向的情况下,异步命令的标准输入将从 重定向/dev/null
。
为什么 OP 的命令没有达到预期的效果
尝试的前两个命令是:
steam & > /dev/null 2>/dev/null
steam & > /dev/null 2>&1
这些没有执行预期的重定向的原因stdout
是stderr
是由于上述运算顺序/运算符优先级规则如上所述。具体来说,&
运算符首先按从左到右的顺序出现。它应用于第一个单词,即命令steam
,并将其发送到后台运行,作为异步命令. stdin
连接到/dev/null
,而stdout
和stderr
保持连接到控制伪终端 /pty
. 下文将对此进行进一步解释。
但首先...