Differences between revisions 1 and 15 (spanning 14 versions)
Revision 1 as of 2007-05-02 18:48:09
Size: 2281
Editor: redondos
Comment:
Revision 15 as of 2010-02-11 21:49:50
Size: 3390
Editor: GreyCat
Comment: another example
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[Anchor(faq2)]]
== How can I store the return value of a command in a variable? ==
Well, that depends on exactly what you mean by that question. Some people want to store the command's ''output'' (either stdout, or stdout + stderr); and others want to store the command's ''exit status'' (0 to 255, with 0 typically meaning "success").
<<Anchor(faq2)>>
== How can I store the return value/output of a command in a variable? ==
Well, that depends whether you want to store the command's ''output'' (either stdout, or stdout + stderr) or its ''exit status'' (0 to 255, with 0 typically meaning "success").
Line 5: Line 5:
If you want to capture the output: If you want to capture the output, you use [[CommandSubstitution|command substitution]]:
Line 23: Line 23:
    var2=$? # the assignment to var1 has no effect on command's exit status, which is still in $?     var2=$?
Line 25: Line 25:
The assignment to {{{var1}}} has no effect on {{{command}}}'s exit status, which is still in {{{$?}}}.
Line 26: Line 27:
If you don't ''actually'' want the exit status, but simply want to take an action upon success or failure: If you don't ''actually'' want to store the exit status, but simply want to take an action upon success or failure:
Line 29: Line 30:
    if command
   
then
    if command; then
Line 41: Line 41:
}}}

Or if you want to capture stdout as well as taking action on success/failure, without explicitly storing and checking the exit status:

{{{
    if output=$(command); then
        echo "it succeeded"
    ...
Line 55: Line 63:
    var=$(command 3>&2 2>&1 1>&3-) # Save stderr, send stdout to stderr
Line 63: Line 72:

    # Or this alternative:
    { var=$(command 2>&1 1>&3-) ;} 3>&1 # Capture stderr, let stdout through.
Line 65: Line 77:
In the last example above, note that {{{1>&3-}}} duplicates FD 3 and stores a copy in FD 1, and then closes FD 3.
Line 66: Line 80:

Well, you can use a horrible hack like:
{{{
   result=$( { stdout=$(cmd) ; } 2>&1; echo "this line is the separator"; echo "$stdout")
   var_out=${result#*this line is the separator$'\n'}
   var_err=${result%$'\n'this line is the separator*}
}}}
Obviously, this is not robust, because either the standard output or the standard error of the command could contain whatever separator string you employ.

''Note: the original question read, "How can I store the return value of a command in a variable?" This was, verbatim, an actual question asked in #bash.''

----
CategoryShell

How can I store the return value/output of a command in a variable?

Well, that depends whether you want to store the command's output (either stdout, or stdout + stderr) or its exit status (0 to 255, with 0 typically meaning "success").

If you want to capture the output, you use command substitution:

    var=$(command)      # stdout only; stderr remains uncaptured
    var=$(command 2>&1) # both stdout and stderr will be captured

If you want the exit status:

    command
    var=$?

If you want both:

    var1=$(command)
    var2=$?

The assignment to var1 has no effect on command's exit status, which is still in $?.

If you don't actually want to store the exit status, but simply want to take an action upon success or failure:

    if command; then
        echo "it succeeded"
    else
        echo "it failed"
    fi

Or (shorter):

    command && echo "it succeeded" || echo "it failed"

Or if you want to capture stdout as well as taking action on success/failure, without explicitly storing and checking the exit status:

    if output=$(command); then
        echo "it succeeded"
    ...

What if you want the exit status of a command in a few that are piped to each other? Use the PIPESTATUS array (BASH only). Say you want the exit status of grep in the following:

    grep foo somelogfile | head -5
    result=${PIPESTATUS[0]}

Now, some trickier stuff. Let's say you want only the stderr, but not stdout. Well, then first you have to decide where you do want stdout to go:

    var=$(command 2>&1 >/dev/null)  # Save stderr, discard stdout.
    var=$(command 2>&1 >/dev/tty)   # Save stderr, send stdout to the terminal.
    var=$(command 3>&2 2>&1 1>&3-)  # Save stderr, send stdout to stderr

It's possible, although considerably harder, to let stdout "fall through" to wherever it would've gone if there hadn't been any redirection. This involves "saving" the current value of stdout, so that it can be used inside the command substitution:

    exec 3>&1                    # Save the place that stdout (1) points to.
    var=$(command 2>&1 1>&3)     # Run command.  stderr is captured.
    exec 3>&-                    # Close FD #3.

    # Or this alternative:
    { var=$(command 2>&1 1>&3-) ;} 3>&1 # Capture stderr, let stdout through.

In the last example above, note that 1>&3- duplicates FD 3 and stores a copy in FD 1, and then closes FD 3.

What you cannot do is capture stdout in one variable, and stderr in another, using only FD redirections. You must use a temporary file to achieve that one.

Well, you can use a horrible hack like:

   result=$( { stdout=$(cmd) ; } 2>&1; echo "this line is the separator"; echo "$stdout")
   var_out=${result#*this line is the separator$'\n'}
   var_err=${result%$'\n'this line is the separator*}

Obviously, this is not robust, because either the standard output or the standard error of the command could contain whatever separator string you employ.

Note: the original question read, "How can I store the return value of a command in a variable?" This was, verbatim, an actual question asked in #bash.


CategoryShell

BashFAQ/002 (last edited 2023-05-11 13:36:34 by emanuele6)