Capture both stdout and stderr in Bash
There is no way to capture both without temp file.
You can capture stderr to variable and pass stdout to user screen (sample from here):
exec 3>&1 # Save the place that stdout (1) points to.
output=$(command 2>&1 1>&3) # Run command. stderr is captured.
exec 3>&- # Close FD #3.
# Or this alternative, which captures stderr, letting stdout through:
{ output=$(command 2>&1 1>&3-) ;} 3>&1
But there is no way to capture both stdout and stderr:
What you cannot do is capture stdout in one variable, and stderr in another, using only FD redirections. You must use a temporary file (or a named pipe) to achieve that one.
Capture stdout from a script?
Setting stdout
is a reasonable way to do it. Another is to run it as another process:
import subprocess
proc = subprocess.Popen(["python", "-c", "import writer; writer.write()"], stdout=subprocess.PIPE)
out = proc.communicate()[0]
print out.upper()
Capture stdout and stderr into different variables
Ok, it got a bit ugly, but here is a solution:
unset t_std t_err
eval "$( (echo std; echo err >&2) \
2> >(readarray -t t_err; typeset -p t_err) \
> >(readarray -t t_std; typeset -p t_std) )"
where (echo std; echo err >&2)
needs to be replaced by the actual command. Output of stdout is saved into the array $t_std
line by line omitting the newlines (the -t
) and stderr into $t_err
.
If you don't like arrays you can do
unset t_std t_err
eval "$( (echo std; echo err >&2 ) \
2> >(t_err=$(cat); typeset -p t_err) \
> >(t_std=$(cat); typeset -p t_std) )"
which pretty much mimics the behavior of var=$(cmd)
except for the value of $?
which takes us to the last modification:
unset t_std t_err t_ret
eval "$( (echo std; echo err >&2; exit 2 ) \
2> >(t_err=$(cat); typeset -p t_err) \
> >(t_std=$(cat); typeset -p t_std); t_ret=$?; typeset -p t_ret )"
Here $?
is preserved into $t_ret
Tested on Debian wheezy using GNU bash
, Version 4.2.37(1)-release (i486-pc-linux-gnu).
How to capture / redirect stdout/stderr from a source command into a variable (in a bash script)?
Surprisingly tricky question!
My first thought was to use a named pipe (mkfifo(1)
), but those have a finite buffer size, so if the source
d script fills up the buffer the script would hang. And you can't use a background process to drain the buffer because you want the output in a variable in the original process eventually.
I'm sure there's a way to make it work entirely in memory, but in the end I think a simple and stupid redirect to a temporary file is the most straightforward and robust solution:
OUTPUT_FILE=$(mktemp)
source other_script.sh >$OUTPUT_FILE 2>&1
OUTPUT="$(< "$OUTPUT_FILE")"
rm -f "$OUTPUT_FILE"
(See this question and in particular BashFAQ 062 for security implications of mktemp
though.)
Capture stdout to a variable but still display it in the console
Duplicate &1
in your shell (in my example to 5) and use &5
in the subshell (so that you will write to stdout (&1
) of the parent shell):
exec 5>&1
FF=$(echo aaa|tee >(cat - >&5))
echo $FF
This will print "aaa" two times, once because of the echo in the subshell, and the second time it prints the value of the variable.
In your code:
exec 5>&1
VAR1=$(for i in {1..5}; do sleep 1; echo $i; done | tee >(cat - >&5))
# use the value of VAR1
How to capture stdout output from a Python function call?
Try this context manager:
from io import StringIO
import sys
class Capturing(list):
def __enter__(self):
self._stdout = sys.stdout
sys.stdout = self._stringio = StringIO()
return self
def __exit__(self, *args):
self.extend(self._stringio.getvalue().splitlines())
del self._stringio # free up some memory
sys.stdout = self._stdout
Usage:
with Capturing() as output:
do_something(my_object)
output
is now a list containing the lines printed by the function call.
Advanced usage:
What may not be obvious is that this can be done more than once and the results concatenated:
with Capturing() as output:
print('hello world')
print('displays on screen')
with Capturing(output) as output: # note the constructor argument
print('hello world2')
print('done')
print('output:', output)
Output:
displays on screen
done
output: ['hello world', 'hello world2']
Update: They added redirect_stdout()
to contextlib
in Python 3.4 (along with redirect_stderr()
). So you could use io.StringIO
with that to achieve a similar result (though Capturing
being a list as well as a context manager is arguably more convenient).
Capture stdout to variable and get the exit statuses of foreground pipe
You can:
Use a temporary file to pass PIPESTATUS.
tmp=$(mktemp)
out=$(pipeline; echo "${PIPESTATUS[@]}" > "$tmp")
PIPESTATUS=($(<"$tmp")) # Note: PIPESTATUS is overwritten each command...
rm "$tmp"Use a temporary file to pass
out
.tmp=$(mktemp)
pipeline > "$tmp"
out=$(<"$tmp"))
rm "$tmp"Interleave output with pipestatus. For example reserve the part from last newline character till the end for PIPESTATUS. To preserve original return status I think some temporary variables are needed:
out=$(pipeline; tmp=("${PIPESTATUS[@]}") ret=$?; echo $'\n' "${tmp[@]}"; exit "$ret"))
pipestatus=(${out##*$'\n'})
out="${out%$'\n'*}"
out="${out%%$'\n'}" # remove trailing newlines like command substitution doestested with:
out=$(false | true | false | echo 123; echo $'\n' "${PIPESTATUS[@]}");
pipestatus=(${out##*$'\n'});
out="${out%$'\n'*}"; out="${out%%$'\n'}";
echo out="$out" PIPESTATUS="${pipestatus[@]}"
# out=123 PIPESTATUS=1 0 1 0
Notes:
- Upper case variables by convention should be reserved by exported variables.
Is it possible to capture the stdout from the sh DSL command in the pipeline
Now, the sh
step supports returning stdout by supplying the parameter returnStdout
.
// These should all be performed at the point where you've
// checked out your sources on the slave. A 'git' executable
// must be available.
// Most typical, if you're not cloning into a sub directory
gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
// short SHA, possibly better for chat notifications, etc.
shortCommit = gitCommit.take(6)
See this example.
Related Topics
Datetime Dtypes in Pandas Read_Csv
"Too Many Values to Unpack" Exception
Moving Matplotlib Legend Outside of the Axis Makes It Cutoff by the Figure Box
Finding Multiple Occurrences of a String Within a String in Python
Multiprocessing: Understanding Logic Behind 'Chunksize'
Working with Big Data in Python and Numpy, Not Enough Ram, How to Save Partial Results on Disc
Assigning to Variable from Parent Function: "Local Variable Referenced Before Assignment"
Python Multiprocessing Safely Writing to a File
How to Solve a Pair of Nonlinear Equations Using Python
Python Cannot Handle Numbers String Starting with 0. Why
Remove and Replace Printed Items
Turn a String into a Valid Filename
How to Set Environment Variables in Pycharm
How to Check If Type of a Variable Is String
Python Sharing a Lock Between Processes
What's the Deal with Python 3.4, Unicode, Different Languages and Windows