3

I have a question related to how to fork stdout in two directions but with a different twist. (I already know about tee! :)

I'd like the output both to appear as is (tee to console?) and to be piped to a further refinement.

Example: I have

ps -ef | grep -i something

now I'd like both to see this result and further refine it, e.g. with

| awk '{print "epwdx "$2}'

Of course I can run the two commands sequentially and capture all the results, but sometimes I'd like to run them as a unit, perhaps increasing the odds that they tell a consistent current truth.

Maybe there's a way using other tricks (such as -, 2>, &2, or the like), but I don't see one yet.

Tim
  • 31

5 Answers5

5

If you want to pull output from the middle of a pipe to the terminal, you can tee it to /dev/tty (or /dev/stderr).

This should print the output of something to the terminal, and direct the same through somefilter to the output file.

somecmd | tee /dev/tty | somefilter > output 

Though if you want to review the output later, it might be easier to just save both the final and intermediate output to files, and then review those.

Though, if all you want is to filter the set of processes shown by ps, or the fields it prints, the program does have some builtin options for that, too. See the manual for "Process selection", "Output format" and "Format specifiers".

ilkkachu
  • 138,973
3

You could use pee if you have it:

pee is like tee but for pipes. Each command is run and fed a copy of the standard input. The output of all commands is sent to stdout. Note that while this is similar to tee, a copy of the input is not sent to stdout, like tee does.

It seems that you will have to implicitly specify a command which copies the input to STDOUT:

ps -ef | pee "cat" "grep -i something"
3

You can use tee with process substitution like

ps -ef | grep -i something | tee >(awk '{print "epwdx "$2}')

though I think @roaima provided a good, all awk solution that's probably the best way to go

Eric Renouf
  • 18,431
2

As I (almost) suggested in a comment, you could use something like this:

ps -ef | grep -i something | tee /dev/stderr | awk '{print "epwdx "$2}'

However, it's also possible to modify the awk command, particularly if you're using GNU awk (gawk), with something like this that removes the need for the grep:

ps -ef | awk '
    BEGIN {IGNORECASE=1}
    /something/ { print ">> Matched 'something' here:", $0; print "epwdx "$2 }
'

(The entire awk statement can sit comfortably on one line if you prefer. Just remove the newlines. I've split it here for readability.)

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
0

As far as i know this can not be done just with file descriptors and seems that the trick suggested with tee >/dev/tty is enough to do your job.

Just for sharing info, i do this job with a function in my bash profile like this:

function teee { a="$(</dev/stdin)";echo -e "pipe in\n$a\npipe out\n" >/dev/stderr; echo "$a"; }

Testing:

$ cat file11 |teee|grep -Po '[A-Za-z]+[\s|\w]+,\s[0-9]+' file11 | teee |awk '{print $2}'
pipe in
Ubuntu, 120, 143, 154
Yggdrasil, 144, 170-171
Yood, Charles, 6
We Were Young, Bob, 178-179
Zawinski, Jamie, 204
pipe out

pipe in
Ubuntu, 120
Yggdrasil, 144
Charles, 6
Bob, 178
Jamie, 204
pipe out

120
144
6
178
204