执行stdout重定向到文件的脚本。所以/ 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
答案 0 :(得分:5)
我怀疑,但这在很大程度上取决于你的shell的行为方式。您看到的文件描述符是:
描述符10和11在exec上关闭,因此不会出现在ls
进程中。然而,在分叉之前,为ls 准备了0-2。我在破折号(Debian Almquist shell)中看到了这种行为,但在bash(Bourne再次shell)中却没有。 Bash反而在分叉后执行文件描述符操作,并且顺便使用255而不是10用于脚本。在分叉后执行更改意味着它不必恢复父级中的描述符,因此它没有备份副本到dup2。
答案 1 :(得分:3)
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
重定向),然后将11恢复到其ls
命令完成后自己的标准输出。