Shell – bottomless tee

io-redirectionpipeshelltee

I was just playing around in the terminal and I did this:

printf 'some string\n' | {
    tee /dev/fd/3 | {
        : && sed 's/some/string/'
    }
} 3>&0

I was really surprised when I was met with a screen full of:

string string
string string
string string
...

It went on pretty much forever. I pared it down some, and to better demonstrate, maybe try this:

echo | tee /dev/fd/0 | sed =

For me, it presents output like:

<num>
#blank
<num+1>
#blank
...

And so on. The few times I've tried it by the time I could hit CTRL+C I was at line 200k+. I tried this in bash, dash, sh, and zsh and all present the same results.

What is going on there? How are the file-descriptors passing over that |pipe between, what I thought were, separate processes? Is this reliable and/or expected behavior? Are there other ways to generate this effect?

For reference:

echo '#blank' | {
    uname -r
    readlink -f /dev/fd/0
    tee /dev/fd/0
} | sed '=;5q'

OUTPUT

1
3.14.6-1-ARCH
2
/proc/24925/fd/pipe:[5851017]
3
#blank
4
#blank
5
#blank

Best Answer

/dev/fd/0 is the current process's standard input; tee writes its input to both to the file(s) you give it and to stdout. So tee is reading a (blank) line, then writing that line to both stdout (sed) and its own input, where it reads the line it just wrote, writes it to stdout and its own input, etc., creating an infinite loop of (empty) lines*. The sed command just prints the line number and then the line.

echo --> tee --> sed
      ^---+

* When provided more input than just a simple echo, this command will loop over the input, repeating it over and over.

Note: OSX (BSD) doesn't let you write to /dev/fd/0, so you can't do this.

Related Question