子进程中的 stdout 和 stderr 重定向

stdout and stderr redirection in child process

如果我 运行 一个像这样的 Bash 脚本:

./script.sh 2>&1

stderr 将被重定向到 stdout

如果脚本调用内部的一些工具(例如ls)或产生一个新进程,这些会 子进程的 stderr 也被重定向到 stdout?

是的,简短的回答。您可以自己尝试一下:

$ (>&1 echo "STDOUT is gone"; >&2 echo "I'm still here") > /dev/null
I'm still here
parent 进程的

STDOUT [我正在用大括号开始一个新的 shell:()] 将被发送到 /dev/null,所有 children 的 STDOUT.

也将如此

在 UNIX/Linux 上创建子进程使用通常称为 fork 的过程。这样做的目的是将当前进程(程序代码,数据,几乎所有内容)的几乎整个进程地址space复制给子进程。进程标识符 (PID) 在子进程中有所不同,但几乎所有其他内容都是相同的。

进程中被复制的项目之一是文件描述符table。这就像一个数组。每个打开的文件都有一个条目,按照惯例,前三个 0、1、2 是 标准流 、stdin、stdout、stderr。这解释了 2>&1 中使用的数字。我们做重定向的时候,就是这三个入口在child里面被改变了。这是由 shell 完成的,因为在这个阶段我们的子进程是另一个 shell 进程。

现在是神奇的部分,通常称为 exec。如果我们想运行一个不同的程序,比如ls,我们可以在进程内切换程序。所以现在新程序从头开始,但保留了一些核心项目。诸如用户、组、当前目录、umask 和文件描述符 table 之类的东西都保留下来供新程序使用。

因此,如果文件描述符 table 先前已更改,则新程序 会继承 这些更改。没有什么可以阻止程序覆盖这些设置并使用不同的文件,但很少这样做。

所有这些行为都是默认的。程序可以更改跨 fork/exec 边界保留哪些文件描述符和其他项目,但它们通常不会。