无底T恤?

mik*_*erv 3 shell pipe io-redirection tee

我只是在终端玩,我这样做了:

printf 'some string\n' | {
    tee /dev/fd/3 | {
        : && sed 's/some/string/'
    }
} 3>&0
Run Code Online (Sandbox Code Playgroud)

当我看到一个充满屏幕的屏幕时,我真的很惊讶:

string string
string string
string string
...
Run Code Online (Sandbox Code Playgroud)

它几乎一直持续下去。我削减了一些,为了更好地展示,也许试试这个:

echo | tee /dev/fd/0 | sed =
Run Code Online (Sandbox Code Playgroud)

对我来说,它显示如下输出:

<num>
#blank
<num+1>
#blank
...
Run Code Online (Sandbox Code Playgroud)

等等。有几次我在我可以打的时候尝试过CTRL+C我在 200k+ 线上。我在bashdashsh和 中尝试了这个,zsh并且都呈现相同的结果。

那里发生了什么?文件描述符如何在|pipe我认为的独立进程之间传递它?这是可靠的和/或预期的行为吗?还有其他方法可以产生这种效果吗?

以供参考:

echo '#blank' | {
    uname -r
    readlink -f /dev/fd/0
    tee /dev/fd/0
} | sed '=;5q'
Run Code Online (Sandbox Code Playgroud)

输出

1
3.14.6-1-ARCH
2
/proc/24925/fd/pipe:[5851017]
3
#blank
4
#blank
5
#blank
Run Code Online (Sandbox Code Playgroud)

Kev*_*vin 7

/dev/fd/0是当前进程的标准输入;tee将其输入写入您提供的文件和标准输出。因此,tee正在读一(空白)行,然后写该行到标准输出(sed)和它自己的输入,它读取它只是写了一行,将它写入到stdout和自己的输入等,创造了一个无限循环(空)行*。该sed命令只打印行号,然后打印行。

echo --> tee --> sed
      ^---+
Run Code Online (Sandbox Code Playgroud)

* 当提供比简单的更多的输入时echo,此命令将循环输入,一遍又一遍地重复。

注意:OSX (BSD) 不允许您写入/dev/fd/0,因此您不能这样做。

  • 那是 Linux 特有的。在 linux 上 /dev/fd/x 是资源的符号链接。在这种情况下,资源就像一个命名管道,因此在写入模式下打开 /dev/fd/3,不会像在其他系统上那样复制 fd 3,而是打开(以不同模式(WR 而不是 RD) )) 管道,所以你得到了管道的写入端(另一端是在 3 上打开的)。 (2认同)