2

I've got a long running process and I want to capture a tiny bit of data from the big swath of output.

I can do this by piping it through grep, but then I can't watch it spew out all the other info.

I basically want grep to save what it finds into a variable and leave stdout alone. How can I do that?

6
  • 1
    not variable, but you could use tee to save the results to a file and continue seeing the output on terminal
    – Sundeep
    Commented Nov 21, 2019 at 2:28
  • How about: command | tee >(grep whatever).
    – tshiono
    Commented Nov 21, 2019 at 2:29
  • @tshiono echo foobar | tee >(\grep -o ob) looks close. Can I get that into a var though?
    – mpen
    Commented Nov 21, 2019 at 2:41
  • where do you intend to "look" at the contents of your variable? Once you have a process occupying a terminal window that is "scrolling" some log info, where can you then look at a variable on the same screen? Please flesh out your expected use case so we can brainstorm. (Saving stuff to a separate file lets you look at that reduced set from a separate window/terminal, something you can't really do with just an assignment to a variable, if I understand your Q ;-? ) Good luck.
    – shellter
    Commented Nov 21, 2019 at 2:45
  • 1
    so, following on from above, command | tee >(grep whatever > specialOut) .... You could then assign like var=$(< specialOut); echo "$var". Good luck.
    – shellter
    Commented Nov 21, 2019 at 2:47

3 Answers 3

4

With tee, process substitution, and I/O redirection:

{ var=$(cmd | tee >(grep regexp) >&3); } 3>&1
1
  • 1
    { X=$(echo foobar | tee >(grep -Pom1 b..) >&3); } 3>&1; echo "$X" Awesome!
    – mpen
    Commented Nov 22, 2019 at 5:13
0

There isn't any way to use a variable like that. It sounds like you want to write your own filter:

./some_long_program | tee >(my_do_stuff.sh)

Then, my_do_stuff.sh is:

#!/bin/bash
while read line; do
    echo "$line" | grep -q 'pattern' || continue
    VARIABLE=$line   # Now it's in a variable
done

If you have the storage space, this is probably more like what you want:

./some_long_program | tee /tmp/slp.log

Then, simply:

grep 'pattern' /tmp/slp.log && VARIABLE=true

or:

VARIABLE=$(grep 'pattern' /tmp/slp.log)

This will let you run the grep at any time. I don't think the variable really adds anything though.

EDIT:

@mpen Based on your last answer above, it sounds like you want to use xargs. Try:

(echo 1 ; sleep 5 ; echo 2) | xargs -L1 echo got:

The -L1 will run the command for every instance found, otherwise it grabs lots of stdin and passes them all (up to some maximum) to the command at once. You'll still want to use this via tee if you want to see all the command output as well:

./some_long_program | tee >(grep 'pattern' | xargs -L1 ./my_do_stuff.sh)

0

I think this can be done a little more simply if we tee to /dev/tty:

❯ BAR=$(echo foobar | tee /dev/tty | grep -Pom1 b..); echo "[$BAR]"
foobar
[bar]

Not the answer you're looking for? Browse other questions tagged or ask your own question.