drjrm3
drjrm3

Reputation: 4718

Redirect output to 3 different files based on content

I have some legacy bash code that I am running and want to insert print statements which should go to stdout. I want anything that would have gone to stdout to go to out.out and anything that would have gone to stderr to go to err.err.

Running myCode.sh 2> err.err 1> out.out will print everything out as normal, but I'd like to put in print statements like echo "NewStatement: I am at this point in the code" and then somehow pre-grep for NewStatement and send it to stdout, while everything else gets treated as normal.

In essence I would like to:

1) Send anything in stdout containing NewStatement to stdout

2) Send anything in stdout not containing NewStatement to out.out

3) Send anything in stderr to err.err

is this possible?

Upvotes: 0

Views: 97

Answers (3)

Fred
Fred

Reputation: 7005

It is very easy. First, the "beginner" solution.

Create a wrapper script (or wrapper function in your main script) which will contain something like this :

#!/bin/bash

while read line || [[ $line ]]
do
  if
    [[ $line =~ NewStatement ]]
  then
    echo "$line"
  else
    echo "$line" >> out.out
  fi
done< <("$@" 2>err.err)

Then, simply call your script like this (assuming everything is executable and in the current directory :

./wrapper myCode.sh

The mode "advanced" solution uses a file descriptor to open the target file for writing.

#!/bin/bash

exec 3> out.out # Open file descriptor 3 for writing to file

while read line || [[ $line ]]
do
  if
    [[ $line =~ NewStatement ]]
  then
    echo "$line"
  else
    echo "$line" >> &3
  fi
done< <("$@" 2>err.err)

exec 3>&- # Close file descriptor

You could have many file descriptors to perform output to many separate files based on arbitrary complex conditions.

Upvotes: 0

clt60
clt60

Reputation: 63952

Alternatively, you can

myCode.sh 2>err.err | tee >(grep -v NewStatement > out.out) | grep NewStatement

The tee duplicates everything from his stdin, so

  • tee-ed stream is filtered by grep -v patt (e.g. doesn't contain) and redirected
  • the stdout if filtered by grep patt (e.g. only lines when contain)

This can be repeated any times, like

cmd | tee >(cmd1) >(cmd2) >(cmd3) | cmd

Upvotes: 1

anubhava
anubhava

Reputation: 785631

You can do it like this:

>out.out

./myCode.sh 2> err.err 1> >(awk '!/^NewStatement/{print > "out.out"; next} 1')

awk command inside process substitution prints to out.out if line doesn't start with NewStatement. Otherwise lines starting with NewStatement are printed to stdout.

Upvotes: 1

Related Questions