【发布时间】:2015-08-18 22:58:35
【问题描述】:
如果我运行这样的 Bash 脚本:
./script.sh 2>&1
stderr 将被重定向到stdout。
如果脚本调用内部的某些工具(例如ls)或产生一个新进程,这些
子进程的stderr 也重定向到stdout?
【问题讨论】:
标签: bash unix process stdout stderr
如果我运行这样的 Bash 脚本:
./script.sh 2>&1
stderr 将被重定向到stdout。
如果脚本调用内部的某些工具(例如ls)或产生一个新进程,这些
子进程的stderr 也重定向到stdout?
【问题讨论】:
标签: bash unix process stdout stderr
是的,这是简短的回答。你可以自己试试:
$ (>&1 echo "STDOUT is gone"; >&2 echo "I'm still here") > /dev/null
I'm still here
父进程的STDOUT [我正在用大括号启动一个新的shell:()] 将被发送到/dev/null,所有子进程的STDOUT 也将发送到。
【讨论】:
在 UNIX/Linux 上创建子进程使用通常称为 fork 的过程。这样做的目的是将当前进程的几乎整个进程地址空间(程序代码、数据、几乎所有内容)复制到子进程中。进程标识符 (PID) 在子进程中有所不同,但几乎所有其他内容都相同。
进程中被复制的项目之一是文件描述符表。这就像一个数组。每个打开的文件都有一个条目,按照惯例,前三个 0、1、2 是标准流、stdin、stdout、stderr。这解释了2>&1 中使用的数字。当我们进行重定向时,这三个条目在子节点中发生了更改。这是由 shell 完成的,因为在这个阶段我们的子进程是另一个 shell 进程。
现在是神奇的部分,通常称为 exec。如果我们想运行不同的程序,比如ls,我们可以在进程内切换程序。所以现在新程序从头开始,但保留了一些核心项目。诸如用户、组、当前目录、umask 和文件描述符表之类的东西都保留给新程序使用。
因此,如果文件描述符表之前已更改,则新程序继承这些更改。没有什么可以阻止程序覆盖这些设置并使用不同的文件,但很少这样做。
所有这些行为都是默认的。程序可以更改跨越 fork/exec 边界保留的文件描述符和其他项目,但它们通常不会。
【讨论】: