This example was submitted (originally in BashFAQ/002) for capturing stdout / stderr to two separate variables.

# Execute a command and store stdout and stderr in two separate variables using only FD redirections
#
# $1: variable name to store stdout command output
# $2: variable name to store stderr command output
# $3: variable name to store command return code
# $4: command to execute
# $5: first command argument
# ...
# $n: last command argument
execute_and_store_std_out_err()
{
  local p_stdout="$1"
  local p_stderr="$2"
  local p_return_code="$3"
  shift 3 || return
  [ "${p_stdout}"      != "stdout"      ] || return
  [ "${p_stdout}"      != ""            ] || return
  [ "${p_stderr}"      != "stderr"      ] || return
  [ "${p_stderr}"      != ""            ] || return
  [ "${p_return_code}" != "return_code" ] || return
  [ "${p_return_code}" != ""            ] || return
  source <(
    {
      {
        {
          stdout="$("$@")"
        } 2>&1
        return_code="$?"
        declare -p stdout return_code >&2
      } |
      {
        stderr="$(cat)"
        declare -p stderr >&2
      }
    } 2>&1
  )
  eval "${p_stdout}"'="${stdout}"'           || return
  eval "${p_stderr}"'="${stderr}"'           || return
  eval "${p_return_code}"'="${return_code}"' || return
}

Sample session:

user@domain:~$ unset out err ret ; declare -p out err ret ; execute_and_store_std_out_err out err ret foo ; declare -p out err ret
bash: declare: out: not found
bash: declare: err: not found
bash: declare: ret: not found
declare -- out="message on stdout"
declare -- err="message on stderr"
declare -- ret="42"
user@domain:~$ 

This is my attempt at cleaning it up, which is difficult because it involves indirection, which is hard to make presentable as a good quality example.

# required wrapper for Bash
unset2() { command unset "$@"; }

# Execute a command and store stdout and stderr in two separate variables using only FD redirections
#
# $1: variable name to store stdout command output
# $2: variable name to store stderr command output
# $3: variable name to store command return code
# $4: command to execute
# $5: first command argument
# ...
# $n: last command argument
function execute_and_store_std_out_err {
    typeset p_stdout=$1
    typeset p_stderr=$2
    typeset p_return_code=$3

    [[
        $p_stdout == !(stdout|) ||
        $p_stderr == !(stderr|) ||
        $p_return_code == !(return_code|)
    ]] || return

    shift 3

    source <(
        {
            {
                {
                    stdout=$("$@")
                } 2>&1
                return_code=$?
                typeset -p stdout return_code >&3
            } |
            {
                stderr=$(</dev/fd/0)
                typeset -p stderr >&3
            }
        } 3>&1
    )

    eval "unset2 -v p_{std{out,err},return_code}; ${p_stdout}=\$stdout ${p_stderr}=\$stderr ${p_return_code}=\$return_code"
}


CategoryExampleCode

CapturingOutput (last edited 2014-11-24 22:31:44 by ormaaj)