3>&1隐含4>&3 5>&3等吗?

ogu*_*ail 29 linux bash shell io-redirection proc-filesystem

我希望

echo foo | tee /proc/self/fd/{3..6} 3>&1
Run Code Online (Sandbox Code Playgroud)

/ proc / self / fd / 4之类的错误而失败:没有这样的文件或目录等,但令我惊讶的是,它输出

foo
foo
foo
foo
foo
Run Code Online (Sandbox Code Playgroud)

就像3>&1导致以下所有描述符都重定向到stdout一样,除非如果我更改3为其他内容则不起作用,例如

echo foo | tee /proc/self/fd/{3..6} 3>&1
Run Code Online (Sandbox Code Playgroud)

有这种行为的解释吗?

Joh*_*ica 29

strace 显示以下系统调用顺序:

$ strace -o strace.log tee /proc/self/fd/{3..6} 3>&1
...
$ cat strace.log
...
openat(AT_FDCWD, "/proc/self/fd/3", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
openat(AT_FDCWD, "/proc/self/fd/4", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 5
openat(AT_FDCWD, "/proc/self/fd/5", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
openat(AT_FDCWD, "/proc/self/fd/6", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 7
...
Run Code Online (Sandbox Code Playgroud)

第一行打开,/proc/self/fd/3并为其分配下一个可用的fd号码,这/proc/self/fd/3是特殊的路径4。打开它的效果类似于在fd 3中进行叠加:fd 4指向与tty 3 fd相同的位置。

每次后续openat()调用都会发生相同的情况。当尘埃落定时,fds 4、5、6和7都是fd 3的副本。

  • 1个 tty
  • 3个 tty
  • 4?tty
  • 5?tty
  • 6?tty
  • 7?tty

请注意,3>&1重定向并不重要。最重要的是,我们要问三通开/proc/self/fd/N在那里ñ已在使用。如果我们放弃了3>&1tee开始,我们应该得到相同的结果/proc/self/fd/2。让我们来看看:

$ echo foo | tee /proc/self/fd/{2..6}
foo
foo
foo
foo
foo
foo
Run Code Online (Sandbox Code Playgroud)

已确认!结果相同。

我们也可以一遍又一遍地重复相同的fd数。达到fd 6时,我们得到的结果相同。到最后一个fd时,它已经打开了足够的描述符以使跳到6成为可能。

$ echo foo | tee /proc/self/fd/{2,2,2,2,6}
foo
foo
foo
foo
foo
foo
Run Code Online (Sandbox Code Playgroud)

  • 花了一些时间按照说明进行操作,但是我想我明白了:每次进程打开文件时,都会为该文件分配下一个可用的文件描述符。/ proc / self / fd对进程的每个文件描述符都包含一个特殊文件,因此打开文件会导致一个新文件出现在该文件中(即使打开的文件本身位于该目录中)。因此,打开`/ proc / self / fd`中的文件会在同一目录中复制该文件,并带有下一个可用的描述符编号。 (2认同)