Capturing `stderr` during Fish's Command Substitution
I've been working on extending Spack's fish-shell support, and I came
across an unusual problem in fish: when I use a nested version of command
substitution (ie. the braces-operator (cmd)
), the outer command Substitution
refused to capture stderr
. This can be demonstrated using the (rather dumb)
following example:
function cause_error
echo "this is a message"
echo "this is another message"
echo "this is an error" 1>&2
return 1
end
function spam
if set output (cause_error)
echo "no error: $status"
else
echo "error: $status"
end
end
To my frustration, I found that calling:
set all_output (spam 2>&1)
does not re-route this is an error
into all_output
as one might expect.
Instead what happens is that, since the command Substitution in spam
(if set
output (cause_error)
) does not redirect stderr
, the stderr
output from
cause_error
cannot be captured by set all_output (spam 2>&1)
. Currently
this seems to be a bug in fish, so I had to be creative by writing
my one capture_all
version of eval
(see below).
Quick and Dirty Solution
While we're waiting for the fish folks to fix this bug, the following
function runs a command using eval
and captures status
,
stdout
, and stderr
.
function capture_all
begin;
begin;
eval $argv[1]
set $argv[2] $status # read sets the `status` flag => capture here
end 2>| read -z __err
end 1>| read -z __out
# output arrays
set $argv[3] (echo $__out | string split \n)
set $argv[4] (echo $__err | string split \n)
return 0
end
It's a bit cumbersome (because everything is managed manually), but it should
do the job. Everything is passed using global variables (that the user
supplies). The command needs to be passed a single string, and the user-defined
target variables need to be set using set -g
beforehand. For example:
set -g stat
set -g out
set -g err
capture_all "cause_error" stat out err
should set
stat
to1
out[1]
tothis is a message
, andout[2]
tothis is another message
err[1]
tothis is an error
.
where the purpose of stat
is to monitor the execution of eval
.