How to store standard error in a variable

后端 未结 18 2144
难免孤独
难免孤独 2020-11-22 12:46

Let\'s say I have a script like the following:

useless.sh

echo \"This Is Error\" 1>&2
echo \"This Is Output\" 

And I have an

相关标签:
18条回答
  • 2020-11-22 13:42

    This post helped me come up with a similar solution for my own purposes:

    MESSAGE=`{ echo $ERROR_MESSAGE | format_logs.py --level=ERROR; } 2>&1`
    

    Then as long as our MESSAGE is not an empty string, we pass it on to other stuff. This will let us know if our format_logs.py failed with some kind of python exception.

    0 讨论(0)
  • 2020-11-22 13:43

    It would be neater to capture the error file thus:

    ERROR=$(</tmp/Error)
    

    The shell recognizes this and doesn't have to run 'cat' to get the data.

    The bigger question is hard. I don't think there's an easy way to do it. You'd have to build the entire pipeline into the sub-shell, eventually sending its final standard output to a file, so that you can redirect the errors to standard output.

    ERROR=$( { ./useless.sh | sed s/Output/Useless/ > outfile; } 2>&1 )
    

    Note that the semi-colon is needed (in classic shells - Bourne, Korn - for sure; probably in Bash too). The '{}' does I/O redirection over the enclosed commands. As written, it would capture errors from sed too.

    WARNING: Formally untested code - use at own risk.

    0 讨论(0)
  • 2020-11-22 13:43

    Here's how I did it :

    #
    # $1 - name of the (global) variable where the contents of stderr will be stored
    # $2 - command to be executed
    #
    captureStderr()
    {
        local tmpFile=$(mktemp)
    
        $2 2> $tmpFile
    
        eval "$1=$(< $tmpFile)"
    
        rm $tmpFile
    }
    

    Usage example :

    captureStderr err "./useless.sh"
    
    echo -$err-
    

    It does use a temporary file. But at least the ugly stuff is wrapped in a function.

    0 讨论(0)
  • 2020-11-22 13:44

    alsoUseless.sh

    This will allow you to pipe the output of your useless.sh script through a command such as sed and save the stderr in a variable named error. The result of the pipe is sent to stdout for display or to be piped into another command.

    It sets up a couple of extra file descriptors to manage the redirections needed in order to do this.

    #!/bin/bash
    
    exec 3>&1 4>&2 #set up extra file descriptors
    
    error=$( { ./useless.sh | sed 's/Output/Useless/' 2>&4 1>&3; } 2>&1 )
    
    echo "The message is \"${error}.\""
    
    exec 3>&- 4>&- # release the extra file descriptors
    
    0 讨论(0)
  • 2020-11-22 13:44
    $ b=$( ( a=$( (echo stdout;echo stderr >&2) ) ) 2>&1 )
    $ echo "a=>$a b=>$b"
    a=>stdout b=>stderr
    
    0 讨论(0)
  • 2020-11-22 13:45

    Capture AND Print stderr

    ERROR=$( ./useless.sh 3>&1 1>&2 2>&3 | tee /dev/fd/2 )
    

    Breakdown

    You can use $() to capture stdout, but you want to capture stderr instead. So you swap stdout and stderr. Using fd 3 as the temporary storage in the standard swap algorithm.

    If you want to capture AND print use tee to make a duplicate. In this case the output of tee will be captured by $() rather than go to the console, but stderr(of tee) will still go to the console so we use that as the second output for tee via the special file /dev/fd/2 since tee expects a file path rather than a fd number.

    NOTE: That is an awful lot of redirections in a single line and the order matters. $() is grabbing the stdout of tee at the end of the pipeline and the pipeline itself routes stdout of ./useless.sh to the stdin of tee AFTER we swapped stdin and stdout for ./useless.sh.

    Using stdout of ./useless.sh

    The OP said he still wanted to use (not just print) stdout, like ./useless.sh | sed 's/Output/Useless/'.

    No problem just do it BEFORE swapping stdout and stderr. I recommend moving it into a function or file (also-useless.sh) and calling that in place of ./useless.sh in the line above.

    However, if you want to CAPTURE stdout AND stderr, then I think you have to fall back on temporary files because $() will only do one at a time and it makes a subshell from which you cannot return variables.

    0 讨论(0)
提交回复
热议问题