9

I am running a program called stm. I want to save only those stderr messages that contain the text "ERROR" in a text file. I also want the messages on the console.

How do I do that in bash?

Joseph Quinsey
  • 9,553
  • 10
  • 54
  • 77
user2339933
  • 93
  • 1
  • 1
  • 5

3 Answers3

16

Use the following pipeline if only messages containing ERROR should be displayed on the console (stderr):

stm |& grep ERROR | tee -a /path/to/logfile

Use the following command if all messages should be displayed on the console (stderr):

stm |& tee /dev/stderr | grep ERROR >> /path/to/logfile

Edit: Versions without connecting standard output and standard error:

stm 2> >( grep --line-buffered ERROR | tee -a /path/to/logfile >&2 )
stm 2> >( tee /dev/stderr | grep --line-buffered ERROR >> /path/to/logfile )
nosid
  • 48,932
  • 13
  • 112
  • 139
  • 7
    `|&` will connect both standard output and standard error to the RHS of the pipeline. – chepner May 01 '13 at 16:12
  • stm |& grep ERROR seems to filter out the messages containing ERROR to the console,but for some reason the teeing to the logfile always seems to return an empty file,Even if I dont want it on the console, stm|& grep ERROR > logfile.txt does'nt work. – user2339933 May 02 '13 at 08:26
3

This looks like a duplicate of How to pipe stderr, and not stdout?

Redirect stderr to "&1", which means "the same place where stdout is going". Then redirect stdout to /dev/null. Then use a normal pipe.

$ date -g
date: invalid option -- 'g'
Try `date --help' for more information.
$
$ (echo invent ; date -g)
invent                                    (stdout)
date: invalid option -- 'g'               (stderr)
Try `date --help' for more information.   (stderr)
$
$ (echo invent ; date -g) 2>&1 >/dev/null | grep inv
date: invalid option -- 'g'
$ 

To copy the output from the above command to a file, you can use a > redirection or "tee". The tee command will print one copy of the output to the console and second copy to the file.

$ stm 2>&1 >/dev/null | grep ERROR > errors.txt

or

$ stm 2>&1 >/dev/null | grep ERROR | tee errors.txt
Community
  • 1
  • 1
Alan Porter
  • 2,339
  • 1
  • 17
  • 12
  • It is almost the same as the question of piping stderr and grepping on it.I just want to log the grepped output to a log file.I am not even concerned about the output on the console so much.For some reason,./stm |& grep ERROR >> log.txt creates an empty log file,although without the redirection to the log file gives the console output on the screen. – user2339933 May 02 '13 at 08:33
0

Are you saying that you want both stderr and stdout to appear in the console, but only stderr (not stdout) that contains "ERROR" to be logged to a file? It is that last condition that makes it difficult to find an elegant solution. If that is what you are looking for, here is my very ugly solution:

touch stm.out stm.err
stm 1>stm.out 2>stm.err & tail -f stm.out & tail -f stm.err & \
wait `pgrep stm`; pkill tail; grep ERROR stm.err > error.log; rm stm.err stm.out

I warned you about it being ugly. You could hide it in a function, use mktemp to create the temporary filenames, etc. If you don't want to wait for stm to exit before logging the ERROR text to a file, you could add tail -f stm.err | grep ERROR > error.log & after the other tail commands, and remove the grep command from the last line.

Markku K.
  • 3,840
  • 19
  • 20
  • Actually the requirement to display on the console is not critical.I just want to mainly to grep stderr and log it onto a text file.I do ./stm |& grep ERROR >> log.txt,but I dont get anything o the text file.When I run ./stm|& grep ERROR,I get the filtered messages on the console. – user2339933 May 02 '13 at 08:54