suppress stderr messages in a bash script

  • Consider the following (slightly silly) script name 'test1.sh':

    #/bin/bash
    #
    sleep 10 &
    echo sleep pid = $!
    pkill sleep
    

    When I run it, I get not only the output of the echo, but bash's reporting of the death of sleep on stderr:

    $ ./test1.sh
    sleep pid = 3551
    ./test1.sh: line 5:  3551 Terminated              sleep 10
    

    In this case, I'd like to suppress the printout to stderr. I know I can do it on the command line, as in:

    $ ./test1.sh 2> /dev/null
    

    ... but is there a way to suppress it from within the script? (I know I could wrap it in a second script and have the wrapper redirect it, but there must be something easier...)

    did you try adding the redirect 2> /dev/null after the pkill sleep ?

    @rahul: yes I did -- pkill isn't generating the message, bash is.

    I used kill instead of pkill and do not get the stderr. strange..

    @rahul: could it be a built in vs non-built in thing? Did you try it with pkill as well?

    yes, i believe it is. I get the same error with pkill, but not with kill. While using kill, i used the pid instead of the proc name.

  • Scott

    Scott Correct answer

    6 years ago

    You're right; pkill isn't generating the message, bash is.  You suggest that

    $ ./test1.sh 2> /dev/null
    

    is a possible solution.  As UVV points out, the equivalent action from within the script is

    exec 2> /dev/null
    

    This redirects the stderr for the script to /dev/null from this statement until it is changed back.  Clumsy ways of changing it back include

    exec 2> /dev/tty
    

    which redirects stderr to the terminal.  This is probably (but not necessarily) where it was originally.

    Or

    exec 2>&1
    

    which sets stderr to be the same as stdout, and is likely to be wrong.

    A more reliable way is

    exec 3>&2
    exec 2> /dev/null
    (do stuff where you don't want to see the stderr.)
    exec 2>&3

    which saves the original stderr in file descriptor 3, and later restores it.

    Other ways to suppress just the announcement of the process death include

    (sleep 10 & pkill sleep) 2> /dev/null
    

    and

    { sleep 10 & pkill sleep;} 2> /dev/null
    

    which change the stderr for only the grouped commands.

    This is such a great, detailed answer. Thank you Sir!

    Are there any dangers associated with saving `stdin` and `stderr` to new file descriptors, sending the original descriptors to `/dev/null` and then restoring them?

    Well, I suppose that, if you ran a program that (unbeknownst to you) wrote to file descriptor 3 (or 4), that operation would fail under normal circumstances.  But the program could be written to ignore the failure and carry on without reporting it; then you’d never know.  But if your file descriptor 1 (or 2) was “parked” on file descriptor 3 (or 4), then that program would suddenly be writing to your script’s stdout or stderr.  But that’s a very contrived example, and still minimal danger.   Did you have something in mind?

    FWIW, I favor Scott's grouped command approach, i.e. `{ sleep 10 & pkill sleep;} 2> /dev/null`

License under CC-BY-SA with attribution


Content dated before 6/26/2020 9:53 AM