4

I'd have supposed this code would have printed "oof" first:

echo foo | tee >(rev) | ( sleep 1 ; cat ; )

Output:

foo
oof

Increasing the sleep time doesn't change the order. Why doesn't that work?


Note that other tools do work as supposed, e.g.: echo foo | pee rev 'sleep 1 ; cat'.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
agc
  • 7,223

2 Answers2

8

In

echo foo | tee >(rev) | (sleep 1; cat)

In bash like in ksh, but unlike zsh, the stdout of rev also is the pipe to (sleep 1; cat).

echo, tee, rev and the (...) subshell are started at the same time, but tee writes foo\n to stdout before the pipe to rev, so in any case, rev will write oof to the pipe after tee writes foo, so oof can only come last. Delaying cat has no incidence.

If you wanted the output of rev not to go through the pipe to (sleep 1; cat), you'd use zsh or do:

{ echo foo 3>&- | tee >(rev >&3 3>&-) 3>&- | (sleep 1; cat) 3>&-; } 3>&1

Note that zsh also has a builtin tee in its multios feature, so you can do:

echo foo > >(rev) > >(sleep 1; cat)

However in:

echo foo > >(rev) | (sleep 1; cat)

The output of rev would go through cat (confusingly considering it doesn't in the echo foo >(echo bar) | (sleep 1; cat) case).

  • Thanks, I needed that! For me this is one of those cases where I knew something, (prior experience juggling three or four pipelines), but failed to correlate it when needed, or perhaps hit my head somewhere... – agc Nov 22 '17 at 16:41
  • @Stéphane, why do you close file descriptor 3 in every command? This example seems to run fine: { echo foo | tee >(rev >&3 ) | tr a-z A-Z ; } 3>&1 – arielCo Dec 15 '17 at 02:30
  • @arielCo For cleaning. They don't need that fd 3. – Stéphane Chazelas Dec 15 '17 at 07:19
1

Using two bash process substitutions, (instead of just one, then a pipe), then dumping the STDOUT to /dev/null, works as expected:

echo foo | tee >(rev) >( sleep 1 ; cat ; ) > /dev/null ; sleep 1

Output:

oof
foo

Notes:

  • the 2nd sleep prevents "foo" from being printed after the command prompt.
  • reducing the sleep delay number to some optimum ought to be better, but I'm not sure what that number should be. 1 is a bit slow, but always seems to work; .01 doesn't always work, (that is, the output is sometimes in the wrong order), .1 seems to work well.
agc
  • 7,223