Linux proc / pid / fd为stdout是11?

用stdout执行一个脚本,redirect到一个文件。 所以/ proc / $$ / fd / 1应该指向那个文件(因为stdout fileno是1)。 但是,该文件的实际fd是11.请解释,为什么。

这是会议:

$ cat hello.sh #!/bin/sh -e ls -l /proc/$$/fd >&2 $ ./hello.sh > /tmp/1 total 0 lrwx------ 1 nga users 64 May 28 22:05 0 -> /dev/pts/0 lrwx------ 1 nga users 64 May 28 22:05 1 -> /dev/pts/0 lr-x------ 1 nga users 64 May 28 22:05 10 -> /home/me/hello.sh l-wx------ 1 nga users 64 May 28 22:05 11 -> /tmp/1 lrwx------ 1 nga users 64 May 28 22:05 2 -> /dev/pts/0 

我有一个怀疑,但这是高度依赖于你的shell的行为。 你看到的文件描述符是:

  • 0:标准输入
  • 1:标准输出
  • 2:标准错误
  • 10:正在运行的脚本
  • 11:脚本正常标准的备份副本

描述符10和11在exec处于关闭状态,所以不会出现在ls进程中。 然而,0-2是分叉准备好的。 我在短划线(Debian Almquist shell)中看到了这种行为,但在bash(Bourne再次shell)中没有。 Bash代替了分叉之后的文件描述符操作,并且顺便使用了255而不是10来代替脚本。 在分叉之后进行更改意味着它不必恢复父级中的描述符,所以它没有从dup2中获得备用副本。

strace的输出可以在这里有所帮助。

相关部分是

 fcntl64(1, F_DUPFD, 10) = 11 close(1) = 0 fcntl64(11, F_SETFD, FD_CLOEXEC) = 0 dup2(2, 1) = 1 stat64("/home/random/bin/ls", 0xbf94d5e0) = -1 ENOENT (No such file or +++++++>directory) stat64("/usr/local/bin/ls", 0xbf94d5e0) = -1 ENOENT (No such file or directory) stat64("/usr/bin/ls", 0xbf94d5e0) = -1 ENOENT (No such file or directory) stat64("/bin/ls", {st_mode=S_IFREG|0755, st_size=96400, ...}) = 0 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, +++++++>child_tidptr=0xb75a8938) = 22748 wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 22748 --- SIGCHLD (Child exited) @ 0 (0) --- dup2(11, 1) = 1 

因此,shell将现有的stdout移动到10(即11)以上的可用文件描述符,然后将现有的stderr移到它自己的stdout(由于>&2重定向),然后当ls命令恢复到它自己的stdout时完成。