'POSIX shell (sh) redirect stderr to stdout and capture stderr and stdout into variables
I would like to redirect stderr to stdout so a terminal prints both of them during a command execution but I would like also to capture both of them into separate variables. I managed to achieve that in Bash (version 4.4.20(1)-release):
#!/bin/bash
echo "terminal:"
{ err="$(find / -maxdepth 2 -iname 'tmp' -type d 2>&1 1>&3 3>&- | tee /dev/stderr)"; ec="$?"; } 3>&1 | tee /dev/fd/4 2>&1; out=$(cat /dev/fd/4)
echo "stdout:" && echo "$out"
echo "stderr:" && echo "$err"
that gives desired:
terminal:
find: ‘/root’: Permission denied
/tmp
/var/tmp
find: ‘/lost+found’: Permission denied
stdout:
/tmp
/var/tmp
stderr:
find: ‘/root’: Permission denied
find: ‘/lost+found’: Permission denied
but I have a problem converting that script into POSIX sh /bin/sh
#!/bin/sh
echo "terminal:"
{ err="$(find / -maxdepth 2 -iname 'tmp' -type d 2>&1 1>&3 3>&- | tee /dev/stderr)"; ec="$?"; } 3>&1 | tee /dev/fd/4 2>&1; out=$(cat /dev/fd/4)
echo "stdout:" && echo "$out"
echo "stderr:" && echo "$err"
gives:
terminal:
tee: /dev/fd/4: No such file or directory
find: ‘/root’: Permission denied
/tmp
/var/tmp
find: ‘/lost+found’: Permission denied
cat: /dev/fd/4: No such file or directory
stdout:
stderr:
/dev/fd/4 does not exist, and there is no /proc/self/fd/4 either.
How to make that script working as a POSIX shell script?
Solution 1:[1]
Well I'm doing this in busybox's ash shell and my options are rather limited, but this is what I came up with that works.
tmpfile=/tmp/some_prefix_stderr.$$
out=$(my_cmd) 2>$tmpfile
result=$?
err=$(cat $tmpfile)
rm $tmpfile
It's not the prettiest, but it works. In general, replace some_prefix with something specific to help avoid collisions, but just having the PID on there will solve that unless you are running multiple threads.
If you can rely upon your program exiting non-zero when there's something to show in stderr, you can simplify it a little:
tmpfile=/tmp/some_prefix_stderr.$$
if ! out=$(my_cmd) 2>$tmpfile; then
# specific behavior here
cat $tmpfile >&2
fi
rm $tmpfile
This is all POSIX compliant. Just be sure to clean up your temp file.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | John Kugelman |
