Search code examples
bashstderr

handle stderr with another script


I have a script (eg. compute.sh) that does something on my Ubuntu 16.04 and may end with error, let's say:

[compute.sh]

#!/bin/bash

...

MISCELLANEOUS OPERATIONS

...

[if error occours]
echo "Error 55a" >&2;
exit 1;

...

echo "Execution ok";
exit 0;

and another script that handles errors (eg. error_handler.sh)

[error_handler.sh]

error=$(cat)

for i in "$@"
do
case $i in
    -u=*|--user=*)
    username="${i#*=}"
    shift
    ;;
    -t=*|--task=*)
    task="${i#*=}"
    shift
    ;;
esac
done

...

SENDS ERROR REPORTING THROUGH AN API LISTENING REMOTELY

...

I'd like to execute compute.sh, redirecting its stderr to error_handler.sh in order to notify my API system the error occourred

if I try this test:

user@ubuntu: echo "test message" | ./error_handler.sh --user=dude --task="simple task"

my error_handler.sh script takes the string "test message" and correctly handles it

how can I redirect only the stderr output to my error_handler.sh script?

EDIT: as sometimes compute.sh may fail without an error message (just by doing exit 1;) I'm not sure if error=$(cat) it's the right way to catch the error message in error_handler.sh. Any other option?

EDIT2: the task may be executed in a crontab, so I need to do all in the same command


Solution

  • The simplest thing to do is create a named pipe to act as the buffer between the two.

    mkfifo errors           # "errors" is an arbitrary file name
    compute.sh 2> errors &  # Run in the background
    error_handler.sh < errors
    

    As one line:

    mkfifo errors; compute.sh 2> errors & error_handler.sh 
    

    Now the two processes run concurrently, and error_handler.sh can read from errors as compute.sh writes to it. The buffer is of bounded size, so compute.sh will automatically block if it gets full. Once error_handler.sh consumes some input, compute.sh will automatically resume. As long as errors aren't produced too quickly (i.e., faster than error_handler.sh can process them), compute.sh will run as if the buffer were unbounded.

    If the buffer is ever emptied, error_handler.sh will block until either more input is available, or until compute.sh closes its end of the pipe by exiting.


    Regular pipeline syntax foo | bar creates an anonymous pipe (or unnamed pipe), and it is just a shortcut for

    mkfifo tmp
    foo > tmp &
    bar < tmp
    

    but limits you to connecting standard output of one command to standard input of another. Using other file descriptors requires contorted redirections. Using named pipes is slightly longer to type, but can be much clearer to read.