Redirect stderr to a bash variable and the stdout to another bash variable without using temporary files
Clash Royale CLAN TAG#URR8PPP
up vote
2
down vote
favorite
func()
echo 'hello'
echo 'This is an error' >&2
a=$(func)
b=???
I'd like to redirect the stderr to b
variable without creating a temporary file.
echo $b
# output should be: "This is an error"
The solution that works but with a temporary file:
touch temp.txt
exec 3< temp.txt
a=$(func 2> temp.txt);
cat <&3
rm temp.txt
So the question is, how do I redirect the stderr
of the bash function func
to the variable b
without the need of a temporary file?
bash shell-script
add a comment |Â
up vote
2
down vote
favorite
func()
echo 'hello'
echo 'This is an error' >&2
a=$(func)
b=???
I'd like to redirect the stderr to b
variable without creating a temporary file.
echo $b
# output should be: "This is an error"
The solution that works but with a temporary file:
touch temp.txt
exec 3< temp.txt
a=$(func 2> temp.txt);
cat <&3
rm temp.txt
So the question is, how do I redirect the stderr
of the bash function func
to the variable b
without the need of a temporary file?
bash shell-script
Related SO question that may be useful: stackoverflow.com/q/962255/1640661
â Anthony Geoghegan
Mar 14 at 12:40
@AnthonyGeoghegan I'd like to store both stderr and stdout in two variables, not only the stderr
â smarber
Mar 14 at 12:54
1
From their comments, it seems the SO questioner also wanted to preserve the stdout (pass it on a pipe). I don't think they got a completely satisfactory answer but I thought the link still might be of interest to you.
â Anthony Geoghegan
Mar 14 at 13:01
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
func()
echo 'hello'
echo 'This is an error' >&2
a=$(func)
b=???
I'd like to redirect the stderr to b
variable without creating a temporary file.
echo $b
# output should be: "This is an error"
The solution that works but with a temporary file:
touch temp.txt
exec 3< temp.txt
a=$(func 2> temp.txt);
cat <&3
rm temp.txt
So the question is, how do I redirect the stderr
of the bash function func
to the variable b
without the need of a temporary file?
bash shell-script
func()
echo 'hello'
echo 'This is an error' >&2
a=$(func)
b=???
I'd like to redirect the stderr to b
variable without creating a temporary file.
echo $b
# output should be: "This is an error"
The solution that works but with a temporary file:
touch temp.txt
exec 3< temp.txt
a=$(func 2> temp.txt);
cat <&3
rm temp.txt
So the question is, how do I redirect the stderr
of the bash function func
to the variable b
without the need of a temporary file?
bash shell-script
asked Mar 14 at 12:09
smarber
3011213
3011213
Related SO question that may be useful: stackoverflow.com/q/962255/1640661
â Anthony Geoghegan
Mar 14 at 12:40
@AnthonyGeoghegan I'd like to store both stderr and stdout in two variables, not only the stderr
â smarber
Mar 14 at 12:54
1
From their comments, it seems the SO questioner also wanted to preserve the stdout (pass it on a pipe). I don't think they got a completely satisfactory answer but I thought the link still might be of interest to you.
â Anthony Geoghegan
Mar 14 at 13:01
add a comment |Â
Related SO question that may be useful: stackoverflow.com/q/962255/1640661
â Anthony Geoghegan
Mar 14 at 12:40
@AnthonyGeoghegan I'd like to store both stderr and stdout in two variables, not only the stderr
â smarber
Mar 14 at 12:54
1
From their comments, it seems the SO questioner also wanted to preserve the stdout (pass it on a pipe). I don't think they got a completely satisfactory answer but I thought the link still might be of interest to you.
â Anthony Geoghegan
Mar 14 at 13:01
Related SO question that may be useful: stackoverflow.com/q/962255/1640661
â Anthony Geoghegan
Mar 14 at 12:40
Related SO question that may be useful: stackoverflow.com/q/962255/1640661
â Anthony Geoghegan
Mar 14 at 12:40
@AnthonyGeoghegan I'd like to store both stderr and stdout in two variables, not only the stderr
â smarber
Mar 14 at 12:54
@AnthonyGeoghegan I'd like to store both stderr and stdout in two variables, not only the stderr
â smarber
Mar 14 at 12:54
1
1
From their comments, it seems the SO questioner also wanted to preserve the stdout (pass it on a pipe). I don't think they got a completely satisfactory answer but I thought the link still might be of interest to you.
â Anthony Geoghegan
Mar 14 at 13:01
From their comments, it seems the SO questioner also wanted to preserve the stdout (pass it on a pipe). I don't think they got a completely satisfactory answer but I thought the link still might be of interest to you.
â Anthony Geoghegan
Mar 14 at 13:01
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
3
down vote
On Linux and with shells that implement here-documents with writable temporary files (like bash
does), you can do:
out=$(ls /dev/null /x 2> /dev/fd/3)
err=$(cat<&3)
3<<EOF
EOF
printf '%s=<%s>n' out "$out" err "$err"
(where ls /dev/null /x
is an example command that outputs something on both stdout and stderr).
With zsh
, you can also do:
() out=$(ls /dev/null /x 2> $1) err=$(<$1); =(:)
(where =(cmd)
is a form of process substitution that uses temporary files, and () code; args
anonymous functions).
In any case, you'd want to use temporary files. Any solution that would use pipes would be prone to deadlocks in case of large outputs. You could read stdout and stderr through two separate pipes and use select()
/poll()
and some reads in a loop to read data as it comes from the two pipes without causing lock-ups, but that would be quite involved and AFAIK, only zsh
has select()
support built-in.
Another approach could be to store one of the streams in temporary memory instead of a temporary file. Like (zsh
or bash
syntax):
IFS= read -rd '' err
IFS= read -rd '' out
< <( out=$(ls /dev/null /x); 2>&1; printf '%s' "$out")
(assuming the command doesn't output any NUL)
Note that $err
will include the trailing newline character.
Other approaches could be to decorate the stdout and stderr differently and remove the decoration upon reading:
out= err=
while IFS= read -r line; do
case $line in
(out:*) out=$out$line#out:$'n';;
(err:*) out=$out$line#err:$'n';;
esac
done < <(
ls /dev/null/x 2>&1 |
grep --label=err --line-buffered -H '^'
)
That assumes GNU grep
and that the lines are short enough. With lines bigger than PIPEBUF (4K on Linux), lines of the output of the two grep
s could end up being mangled together in chunks.
add a comment |Â
up vote
1
down vote
Well, capturing the stderr in one variable and stdout in another variable without temporary file is not easy at all.
Here is an example that works
func()
echo 'hello'
echo 'This is an error' >&2
result=$(
stdout=$(func) ; 2>&1
echo -e "mysuperuniqueseparatorn"
echo -e "$stdoutn"
)
var_out=$result#*mysuperuniqueseparator$'n'
var_err=$result%$'n'mysuperuniqueseparator*
I'm not happy with it because it's a dirty way, redirect the stderr to stdout and put both in one variable with a separator between them and then break it down into two pieces.
Plus :
Obviously, this is not robust, because either the standard output or the standard error of the command could contain whatever separator string you employ.
Taken from here http://mywiki.wooledge.org/BashFAQ/002
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
On Linux and with shells that implement here-documents with writable temporary files (like bash
does), you can do:
out=$(ls /dev/null /x 2> /dev/fd/3)
err=$(cat<&3)
3<<EOF
EOF
printf '%s=<%s>n' out "$out" err "$err"
(where ls /dev/null /x
is an example command that outputs something on both stdout and stderr).
With zsh
, you can also do:
() out=$(ls /dev/null /x 2> $1) err=$(<$1); =(:)
(where =(cmd)
is a form of process substitution that uses temporary files, and () code; args
anonymous functions).
In any case, you'd want to use temporary files. Any solution that would use pipes would be prone to deadlocks in case of large outputs. You could read stdout and stderr through two separate pipes and use select()
/poll()
and some reads in a loop to read data as it comes from the two pipes without causing lock-ups, but that would be quite involved and AFAIK, only zsh
has select()
support built-in.
Another approach could be to store one of the streams in temporary memory instead of a temporary file. Like (zsh
or bash
syntax):
IFS= read -rd '' err
IFS= read -rd '' out
< <( out=$(ls /dev/null /x); 2>&1; printf '%s' "$out")
(assuming the command doesn't output any NUL)
Note that $err
will include the trailing newline character.
Other approaches could be to decorate the stdout and stderr differently and remove the decoration upon reading:
out= err=
while IFS= read -r line; do
case $line in
(out:*) out=$out$line#out:$'n';;
(err:*) out=$out$line#err:$'n';;
esac
done < <(
ls /dev/null/x 2>&1 |
grep --label=err --line-buffered -H '^'
)
That assumes GNU grep
and that the lines are short enough. With lines bigger than PIPEBUF (4K on Linux), lines of the output of the two grep
s could end up being mangled together in chunks.
add a comment |Â
up vote
3
down vote
On Linux and with shells that implement here-documents with writable temporary files (like bash
does), you can do:
out=$(ls /dev/null /x 2> /dev/fd/3)
err=$(cat<&3)
3<<EOF
EOF
printf '%s=<%s>n' out "$out" err "$err"
(where ls /dev/null /x
is an example command that outputs something on both stdout and stderr).
With zsh
, you can also do:
() out=$(ls /dev/null /x 2> $1) err=$(<$1); =(:)
(where =(cmd)
is a form of process substitution that uses temporary files, and () code; args
anonymous functions).
In any case, you'd want to use temporary files. Any solution that would use pipes would be prone to deadlocks in case of large outputs. You could read stdout and stderr through two separate pipes and use select()
/poll()
and some reads in a loop to read data as it comes from the two pipes without causing lock-ups, but that would be quite involved and AFAIK, only zsh
has select()
support built-in.
Another approach could be to store one of the streams in temporary memory instead of a temporary file. Like (zsh
or bash
syntax):
IFS= read -rd '' err
IFS= read -rd '' out
< <( out=$(ls /dev/null /x); 2>&1; printf '%s' "$out")
(assuming the command doesn't output any NUL)
Note that $err
will include the trailing newline character.
Other approaches could be to decorate the stdout and stderr differently and remove the decoration upon reading:
out= err=
while IFS= read -r line; do
case $line in
(out:*) out=$out$line#out:$'n';;
(err:*) out=$out$line#err:$'n';;
esac
done < <(
ls /dev/null/x 2>&1 |
grep --label=err --line-buffered -H '^'
)
That assumes GNU grep
and that the lines are short enough. With lines bigger than PIPEBUF (4K on Linux), lines of the output of the two grep
s could end up being mangled together in chunks.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
On Linux and with shells that implement here-documents with writable temporary files (like bash
does), you can do:
out=$(ls /dev/null /x 2> /dev/fd/3)
err=$(cat<&3)
3<<EOF
EOF
printf '%s=<%s>n' out "$out" err "$err"
(where ls /dev/null /x
is an example command that outputs something on both stdout and stderr).
With zsh
, you can also do:
() out=$(ls /dev/null /x 2> $1) err=$(<$1); =(:)
(where =(cmd)
is a form of process substitution that uses temporary files, and () code; args
anonymous functions).
In any case, you'd want to use temporary files. Any solution that would use pipes would be prone to deadlocks in case of large outputs. You could read stdout and stderr through two separate pipes and use select()
/poll()
and some reads in a loop to read data as it comes from the two pipes without causing lock-ups, but that would be quite involved and AFAIK, only zsh
has select()
support built-in.
Another approach could be to store one of the streams in temporary memory instead of a temporary file. Like (zsh
or bash
syntax):
IFS= read -rd '' err
IFS= read -rd '' out
< <( out=$(ls /dev/null /x); 2>&1; printf '%s' "$out")
(assuming the command doesn't output any NUL)
Note that $err
will include the trailing newline character.
Other approaches could be to decorate the stdout and stderr differently and remove the decoration upon reading:
out= err=
while IFS= read -r line; do
case $line in
(out:*) out=$out$line#out:$'n';;
(err:*) out=$out$line#err:$'n';;
esac
done < <(
ls /dev/null/x 2>&1 |
grep --label=err --line-buffered -H '^'
)
That assumes GNU grep
and that the lines are short enough. With lines bigger than PIPEBUF (4K on Linux), lines of the output of the two grep
s could end up being mangled together in chunks.
On Linux and with shells that implement here-documents with writable temporary files (like bash
does), you can do:
out=$(ls /dev/null /x 2> /dev/fd/3)
err=$(cat<&3)
3<<EOF
EOF
printf '%s=<%s>n' out "$out" err "$err"
(where ls /dev/null /x
is an example command that outputs something on both stdout and stderr).
With zsh
, you can also do:
() out=$(ls /dev/null /x 2> $1) err=$(<$1); =(:)
(where =(cmd)
is a form of process substitution that uses temporary files, and () code; args
anonymous functions).
In any case, you'd want to use temporary files. Any solution that would use pipes would be prone to deadlocks in case of large outputs. You could read stdout and stderr through two separate pipes and use select()
/poll()
and some reads in a loop to read data as it comes from the two pipes without causing lock-ups, but that would be quite involved and AFAIK, only zsh
has select()
support built-in.
Another approach could be to store one of the streams in temporary memory instead of a temporary file. Like (zsh
or bash
syntax):
IFS= read -rd '' err
IFS= read -rd '' out
< <( out=$(ls /dev/null /x); 2>&1; printf '%s' "$out")
(assuming the command doesn't output any NUL)
Note that $err
will include the trailing newline character.
Other approaches could be to decorate the stdout and stderr differently and remove the decoration upon reading:
out= err=
while IFS= read -r line; do
case $line in
(out:*) out=$out$line#out:$'n';;
(err:*) out=$out$line#err:$'n';;
esac
done < <(
ls /dev/null/x 2>&1 |
grep --label=err --line-buffered -H '^'
)
That assumes GNU grep
and that the lines are short enough. With lines bigger than PIPEBUF (4K on Linux), lines of the output of the two grep
s could end up being mangled together in chunks.
edited Mar 14 at 14:13
answered Mar 14 at 13:43
Stéphane Chazelas
280k53515847
280k53515847
add a comment |Â
add a comment |Â
up vote
1
down vote
Well, capturing the stderr in one variable and stdout in another variable without temporary file is not easy at all.
Here is an example that works
func()
echo 'hello'
echo 'This is an error' >&2
result=$(
stdout=$(func) ; 2>&1
echo -e "mysuperuniqueseparatorn"
echo -e "$stdoutn"
)
var_out=$result#*mysuperuniqueseparator$'n'
var_err=$result%$'n'mysuperuniqueseparator*
I'm not happy with it because it's a dirty way, redirect the stderr to stdout and put both in one variable with a separator between them and then break it down into two pieces.
Plus :
Obviously, this is not robust, because either the standard output or the standard error of the command could contain whatever separator string you employ.
Taken from here http://mywiki.wooledge.org/BashFAQ/002
add a comment |Â
up vote
1
down vote
Well, capturing the stderr in one variable and stdout in another variable without temporary file is not easy at all.
Here is an example that works
func()
echo 'hello'
echo 'This is an error' >&2
result=$(
stdout=$(func) ; 2>&1
echo -e "mysuperuniqueseparatorn"
echo -e "$stdoutn"
)
var_out=$result#*mysuperuniqueseparator$'n'
var_err=$result%$'n'mysuperuniqueseparator*
I'm not happy with it because it's a dirty way, redirect the stderr to stdout and put both in one variable with a separator between them and then break it down into two pieces.
Plus :
Obviously, this is not robust, because either the standard output or the standard error of the command could contain whatever separator string you employ.
Taken from here http://mywiki.wooledge.org/BashFAQ/002
add a comment |Â
up vote
1
down vote
up vote
1
down vote
Well, capturing the stderr in one variable and stdout in another variable without temporary file is not easy at all.
Here is an example that works
func()
echo 'hello'
echo 'This is an error' >&2
result=$(
stdout=$(func) ; 2>&1
echo -e "mysuperuniqueseparatorn"
echo -e "$stdoutn"
)
var_out=$result#*mysuperuniqueseparator$'n'
var_err=$result%$'n'mysuperuniqueseparator*
I'm not happy with it because it's a dirty way, redirect the stderr to stdout and put both in one variable with a separator between them and then break it down into two pieces.
Plus :
Obviously, this is not robust, because either the standard output or the standard error of the command could contain whatever separator string you employ.
Taken from here http://mywiki.wooledge.org/BashFAQ/002
Well, capturing the stderr in one variable and stdout in another variable without temporary file is not easy at all.
Here is an example that works
func()
echo 'hello'
echo 'This is an error' >&2
result=$(
stdout=$(func) ; 2>&1
echo -e "mysuperuniqueseparatorn"
echo -e "$stdoutn"
)
var_out=$result#*mysuperuniqueseparator$'n'
var_err=$result%$'n'mysuperuniqueseparator*
I'm not happy with it because it's a dirty way, redirect the stderr to stdout and put both in one variable with a separator between them and then break it down into two pieces.
Plus :
Obviously, this is not robust, because either the standard output or the standard error of the command could contain whatever separator string you employ.
Taken from here http://mywiki.wooledge.org/BashFAQ/002
answered Mar 14 at 15:23
smarber
3011213
3011213
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f430161%2fredirect-stderr-to-a-bash-variable-and-the-stdout-to-another-bash-variable-witho%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Related SO question that may be useful: stackoverflow.com/q/962255/1640661
â Anthony Geoghegan
Mar 14 at 12:40
@AnthonyGeoghegan I'd like to store both stderr and stdout in two variables, not only the stderr
â smarber
Mar 14 at 12:54
1
From their comments, it seems the SO questioner also wanted to preserve the stdout (pass it on a pipe). I don't think they got a completely satisfactory answer but I thought the link still might be of interest to you.
â Anthony Geoghegan
Mar 14 at 13:01