exec内置外壳(第一个细微差别)

exec内置外壳(第一个细微差别)

我试图将程序(Steam)的所有输出重定向到 /dev/null,这样它就不会出现在终端中。

这是我尝试过的 steam & > /dev/null 2>/dev/nullsteam & > /dev/null 2>&1

据我所知,两者都不会抑制其信息。

我的理解是 & 将进程与终端分离,而 > 重定向输入/输出,默认/空白 > 为 stdout,2> 为 stderr。除了这两个之外,还有更多的输出吗?如果我将所有内容重定向,为什么仍然可以看到输出?

答案1

尝试:

steam 2>&1 > /dev/null &

2>&1将 stderr 重定向到 stdout,并将> /dev/nullstdout 重定向到/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 通过execShell 内置. 这可能会影响标准 IO 重定向和子进程树,具体取决于如何调用它。 笔记:虽然这在技术上并不适用于 OP 的特定用例和列出的命令,但我将其包括在这里,因为它是一个需要注意的常见陷阱和警告。

摘自 IEEE Std. 1003.1,2004 版:

exec 实用程序将根据命令中任何重定向的指定打开、关闭和/或复制文件描述符。

如果指定 exec 时不带命令或参数,并且使用关联的重定向语句打开任何编号大于 2 的文件描述符,则无法确定当 shell 调用另一个实用程序时这些文件描述符是否保持打开状态。担心子 shell 可能滥用打开的文件描述符的脚本始终可以显式关闭它们,如以下示例之一所示。

如果 exec 指定了命令,它将用命令替换 shell,而不创建新进程。如果指定了参数,它们将是命令的参数。重定向会影响当前 shell 执行环境。

exec /usr/lib/steam/steam "$@"包装脚本中的行将替换/usr/bin/steam正在执行的/bin/bashshell(按照“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等。stdoutstderrshzshkshcshdash

就 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<&YX>&YX>|YX<&Y-X<>Y, ETC...)

...以及:

  • 控制运算符&,,/ ,,,,,,,,)。;​​​​​​\nnewline||&& ;;;&;;&| |&()

来自Bash 参考手册 § 3.6 重定向

重定向按照其出现的顺序从左到右进行处理。

[...剪切...]

请注意,重定向的顺序很重要。例如,命令

ls > dirlist 2>&1

将标准输出(文件描述符 1)和标准错误(文件描述符 2)定向到文件 dirlist,而命令

ls 2>&1 > dirlist

仅将标准输出定向到文件 dirlist,因为在将标准输出重定向到 dirlist 之前,标准错误已成为标准输出的副本。

&类似地,和其他控制运算符也有一定的运算顺序。

来自Bash 参考手册:2.4 命令列表

列表是由操作符“ ;”、“ &”、“ &&”或“ ”之一分隔的一个或多个管道序列,并且可以选择以“ ”、“ ”或“ ”||之一终止。;&newline

在这些列表运算符中,' &&' 和 ' ||' 具有相同的优先级,其次是 ' ;' 和 ' &',它们具有相同的优先级。

可以出现一个或多个换行符序列来list分隔命令,相当于分号。

最后,具体来说关于以下内容的部分&

如果命令以控制操作符“ &”结束,则 shell 将在子 shell 中异步执行该命令。这称为在背景,这些被称为异步命令。shell 不会等待命令完成,返回状态为0( true)。当作业控制未处于活动状态时(请参阅作业控制),在没有任何显式重定向的情况下,异步命令的标准输入将从 重定向/dev/null

为什么 OP 的命令没有达到预期的效果

尝试的前两个命令是:

  • steam & > /dev/null 2>/dev/null
  • steam & > /dev/null 2>&1

这些没有执行预期的重定向的原因stdoutstderr是由于上述运算顺序/运算符优先级规则如上所述。具体来说,&运算符首先按从左到右的顺序出现。它应用于第一个单词,即命令steam,并将其发送到后台运行,作为异步命令. stdin连接到/dev/null,而stdoutstderr保持连接到控制伪终端 /pty. 下文将对此进行进一步解释。

但首先...

更加连锁的exec混乱!

相关内容