9

How to get stdout to console and pipe to next command at the same time?

I've tried using the Read command as suggested here which worked to get the output of Grep from a Tail of a log file to a variable and then to a log or email, but I'd still like to get the output to stdout console as well: https://unix.stackexchange.com/a/365222/346155

I've tried using Tee as here: https://unix.stackexchange.com/a/47936/346155

I'm using the --line-buffered flag just in case from here: https://stackoverflow.com/a/7162898/4240654

I may be missing something simple about the sdtin logic, but the case from the first link suggests that Bash may not have this simple capability. And that variables cannot read from a subshell.

The fact that echo 'hello' | echo $(</dev/stdin) works, suggests it might be possible. Another way to look at it is, how can I stdout to console within each pipe segment. That should help to debug a long chain of commands, before committing it to a bash script.

EDITS: Something like echo 'hello' | echo $(</dev/stdin) >/dev/stout or echo 'hello' | tee >/dev/stdout | echo 2nd $(</dev/stdin), the latter should output 'hello' twice, but only does so once.

alchemy
  • 597
  • How did you use tee? – Arkadiusz Drabczyk Mar 25 '20 at 17:12
  • I was able to Tee to a log file, but not yet to Stdout console. – alchemy Mar 25 '20 at 17:17
  • Do you want this echo hello | tee >(grep -o h)? – Arkadiusz Drabczyk Mar 25 '20 at 17:28
  • @ArkadiuszDrabczyk In total I want it to (tail log) | grep "keyword" | tee>*OutToConsole* | (read var | echo var | mail ) so I can see the alert line also before it emails.....YES, that was what I was missing.. Grep in a subshell does stsout to console Thanks! .. for the record, so does Echo. – alchemy Mar 25 '20 at 17:32
  • tail log | grep "keyword" | tee >(mail)? – Arkadiusz Drabczyk Mar 25 '20 at 17:37
  • Actually even generateOutput | tee >(grep "keyword") | thenDoOtherStuff works. The linked answer regarding Tee I think was too specific to abstract to a general case. – alchemy Mar 25 '20 at 17:40
  • @ArkadiuszDrabczyk, go ahead and answer in the general case and I will accept. I suppose the question could also be how to output to stdout without a subshell, but someone can try answering that. – alchemy Mar 25 '20 at 17:51
  • The command you showed will not print output of grep, check: echo stuff | tee >(grep -o s) | wc -c – Arkadiusz Drabczyk Mar 25 '20 at 18:04
  • >/dev/stdout -- redirect stdout to stdout. – ctrl-alt-delor Mar 25 '20 at 18:08
  • @ArkadiuszDrabczyk, how interesting, I thought that solved it, but echo 'hello' | tee >(echo hello) | echo 2nd $(</dev/stdin) gives 2 hellos, but in a different order. Grep in place of Echo does the same. I think using Tee as with Kamil's answer is probably the most direct. – alchemy Mar 26 '20 at 03:09

2 Answers2

8

Use tee /dev/tty. Example:

echo "Hello word" | tee /dev/tty | wc -c

tee and /dev/tty are required by POSIX.


In general you can use a name like /dev/tty2 or /dev/pts/7. It doesn't have to be the current terminal, if only you can write to it.

Another way to look at it is, how can I stdout to console within each pipe segment. That should help to debug a long chain of commands, before committing it to a bash script.

I have done something similar conveniently with tmux panes. You can do this with or without tmux.

  1. Prepare as many panes as you need; or console windows, if you prefer.
  2. In each invoke tty to learn the filename of the terminal.
  3. In one of them invoke the pipeline you want to debug, using tee and a different terminal in each step. This pipeline

    command1 | command2 | command3
    

    will become something like

    command1 | tee /dev/pts/4 | command2 | tee /dev/pts/5 | command3
    

    where /dev/pts/4 and /dev/pts/5 are additional terminals (e.g. panes in tmux).

  • You can do that even when not run from a terminal { echo "Hello word" | tee /dev/fd/7 | wc -c; } 7>&1 (ok, not POSIX, and will NOT work on FreeBSD by default). Notice that /dev/tty or /dev/pts/N do not always work: su other_user -c 'echo hi | tee /dev/tty | wc -c' => tee: /dev/tty: No such device or address. But it's not clear for me that it's this that the OP is after ;-) –  Mar 25 '20 at 20:34
  • This is great, exactly what I was looking for! @mosvy, there may be special cases where it doesnt work, and good to know it will translate into a script. What is 7 again? – alchemy Mar 26 '20 at 03:10
1

... | tee log-file-name

This take the stdout of the first command and copies to the log file, and to stdout.