1

Maybe this is duplicate, I have not found any answers though, but how to use pipe to output one command to multiple outpus (e.g. send it to pipe, stdout, or command substitution)?

I have this line:

$ command_with_output1 | tee >(command_with_output2) | command3

And I would like to send output from command_with_output1 to stdout via tee and also to command_with_output2 via >() and also to command3 via |. Is it possible? How to achieve this?

A nonsensical exmaple ,but to demostrate what i meant, could be as follow:

  1. pipe problem
    $ cat <<< "abc" | tee >( > /dev/null) | while read i; do echo "$i"; done
    

This command should output 2 times "abc" (1. - tee, 2. - while read...), but instead output just one:

user@host:~$ cat <<< "abc"| tee >( > /dev/null) | while read i; do echo $i; done
abc #only one, I would expect one more

Therefor I think, the second missing ouput will be "lost" after pipe (pipe won't deliver stdout from tee to stdin of while), because tee probably only works only on files, no pipes (correct me if I am wrong here).

  1. stdout deliver probelm
    cat <<< "abc" | tee >(xargs -I{} bash -c "for i in '{}'; do echo $i; done")
    

Although this command does not use pipe "after" tee, I would also expect to output 2 times "abc" (again tee, and now for i in ...), but yet, outputs only once:

user@Host:~$ cat <<< "abc" | tee >(xargs -I{} bash -c "for i in '{}'; do echo $i; done")
abc #only one, I would expect one more

So to explain: in first command, whether am I right in that, tee does not output to pipe (but rather to file). And for the second command explain, why does not output 2 times, why does not the xargs command deliver the output via '{}' to bash

Herdsman
  • 320
  • 4
  • 20
  • Why aren't you using an additional process substitution for `command3` with `tee`? – Kusalananda May 16 '20 at 13:34
  • Because, the third command is more complicated and have more piped, at the end. But still, without any substitution, tee will not output to `stdout` (e.g. `cmd1 | tee | cmd2`) – Herdsman May 16 '20 at 13:39
  • There's also`pee`, which is a [`tee` for commands](https://unix.stackexchange.com/a/371730/65304) – steeldriver May 16 '20 at 13:40
  • Maybe you could show a more real example and also clarify where the final outputs should go? – Kusalananda May 16 '20 at 13:44
  • @Kusalananda editted – Herdsman May 16 '20 at 14:53
  • @Herdsman if by `stdout` you mean "the terminal" you can just add `/dev/tty` to the `tee` – LL3 May 16 '20 at 15:05
  • Your first command explicitly discards one copy of `abc`. You second command expands `$i` in the _calling_ shell, not in the `bash -c` shell. That command should also look like `xargs -I {} bash -c 'for i do echo "$i"; done' bash {}` or simply `xargs -I {} bash -c 'printf "%s\n" "$@"' bash {}`. – Kusalananda May 16 '20 at 15:18
  • 1) so explicilty `discard` you mean because of the pipe instead of file? That is what I thought. 2) that does not work, `echo "abc" | tee >(xargs -I {} bash -c 'printf "%s\n" "$@"' bash {})`, please send full command – Herdsman May 16 '20 at 15:27
  • @Herdsman 1) No you use `tee >( >/dev/null )`. You can't expect that to produce any output apart from what is sent on the the next part of the pipeline. 2) In what way does it not work. It produces `abc` twice. Once as the output of `tee`, and once as the output of `bash -c`. – Kusalananda May 16 '20 at 15:41

1 Answers1

1

To explain your pipe problem:

Let's break it down into smaller chunks:

$ cat <<< "abc" --> This command passes the string "abc" to the standard input of the command on the left, which is cat.

| tee >( > /dev/null) --> The tee command takes its input from the command cat by reading the standard input, passes the file-output to /dev/null and then writes the string "abc" to standard output.

| while read i; do echo "$i"; done --> The read command reads the string "abc" from standard input and stores the string "abc" to the variable i and then your loop prints the contents of i which is the string "abc" - and only once.

The tee command prints nothing on the terminal because its output is piped to the read command.

You can try this with writing the standard output to a file instead.

user@host:~$ cat <<< "abc"| tee file_name.txt | while read i; do echo $i >> file_name.txt; done; cat file_name.txt
Rasulli
  • 101
  • 4