1

Is there anyway to redirect filtered output to multiple files by running mycommand.sh only once?

Example output should be similar to this:

mycommand.sh | grep --line-buffered -B 1 A >> file1 ; my command.sh | grep --line-buffered -A 1 B >> file2

Or maybe with egrep somehow...

0

2 Answers 2

3

With awk command:

mycommand.sh | awk '/A/{ print > "file1" }/B/{ print > "file2" }'
  • /A/{ print > "file1" } - if a record matches the pattern A print/redirect the whole record into file1
5
  • Hi, I actually use grep --line-buffered since the script generates output during runtime. Also i need before and after in grep. I updated my command to be similar with what i need. Can i do the same with awk?
    – Future
    Commented Jan 25, 2018 at 11:55
  • I know.. this should be the last version :)
    – Future
    Commented Jan 25, 2018 at 12:03
  • No, the files are not being written (that's because of line-buffered needed). However are created by have 0 bytes.
    – Future
    Commented Jan 25, 2018 at 12:14
  • I just found that i can use unbuffer from packet expect or stdbuf before running mycommand.sh and then awk it. (superuser.com/questions/742238/piping-tail-f-into-awk).
    – Future
    Commented Jan 25, 2018 at 12:17
  • BTW, it's not terribly difficult to implement a simple version of grep-like context printing (-A, -B, and -C) in awk or other languages. You just need to store the last N lines that you read in (and print them along with the matching line for -B) or read & print the next N lines following a match (for -A). For -C, store & print N/2 lines before, and print N/2 lines after the match. Print the -- group separators too if you want. You can use an array to store the lines - add new lines onto the end, and delete old lines from the start of the array.
    – cas
    Commented Jan 25, 2018 at 13:56
3

awk is a better tool for this because it's much faster, doesn't need to fork grep or whatever multiple times, and easily scales up to writing to any number files. Ditto for most other scripting languages, like perl or python.

In shell, you can use tee and process substitution. e.g.

mycommand.sh |
  tee >(grep --line-buffered -A 1 B >> file2) |
  grep --line-buffered -B 1 A >> file1

(extra line feeds and indentation added to improve readability. works all on one line if you prefer it ugly and unreadable)

tee writes its input to both stdout (e.g. to the terminal, redirected to a file, or piped to the next command in the pipleline) AND to a file specified on the command line.

In this case, that "file" is a file descriptor provided by process substitution (e.g. another grep command with redirected output, as in the example above).

tee can write to multiple output files (or process substitution file-descriptors) simultaneously. For example:

mycommand.sh |
  tee >(grep --line-buffered -A 1 B >> file2) \
    >(grep --line-buffered -A 1 C >> file3) \
    >(grep --line-buffered -A 1 D >> file4) |
  grep --line-buffered -B 1 A >> file1

This works, but I'd personally use something like @RomanPerekhrest's awk answer.

1
  • The question is “How do I run a command once and use its output as input to multiple programs?”, not “How do I run a command once and search for multiple strings in it?” — that’s just the example  — so I believe that this is really the better answer to the question. Commented Jan 25, 2018 at 23:26

Not the answer you're looking for? Browse other questions tagged .