[Feature] / [Question] / [RFC] Ability to access / propagate command stdout + stderr to the failed block
Description
It appears that today, there is no way to access stdout + stderr of a command which failed (exited with non zero status code) inside the failed block or outside of it as part of the command return value.
I tried multiple approaches without success - please correct me if I'm wrong and I missed something.
Background, Context, Use Case
Today Amber already offers some improved error / failure handling of commands which exited with non-zero status code, but since I don't have access to command stdout + stderr, I can't improve and add additional user-friendly error handling in the failed block (or outside of it)
In ideal world, each program would exit with a different non-zero status code for each error scenario, but that's not a case with majority of the programs today. In a lot of cases only way to determine error type is to parse and inspect the command string output (stdout / stderr).
I know that one workaround I could perhaps use is to redirect command stderr output to stdout, but this is not ideal and still only works in case command exited with zero status code.
Let's take this code for example:
import * from "std"
main (args) {
echo ""
echo "scenario 1 - exit code 0 with failed block"
echo ""
let output = silent $ echo "stdout" ; >&2 echo "stderr" ; exit 0 $ failed {
echo "Should not get here"
}
echo ""
echo "output"
echo "{output}"
echo "status: {status}"
echo "end"
echo ""
echo "scenario 2 - exit code 2"
echo ""
let output = silent $ echo "stdout" ; >&2 echo "stderr" ; exit 2 $ failed {
echo "Inside failed block"
echo "status: {status}"
}
echo ""
echo "output"
echo "{output}"
echo "status: {status}"
echo "end"
echo ""
echo "scenario 3 - exit code 2 with unsafe"
echo ""
let output = silent unsafe $ echo "stdout" ; >&2 echo "stderr" ; exit 2 $
echo ""
echo "output"
echo "{output}"
echo "status: {status}"
echo "end"
}
Output will look like this:
$ bash test.sh
scenario 1 - exit code 0 with failed block
stderr
output
stdout
stauts: 0
end
scenario 2 - exit code 2
stderr
Inside failed block
output
stdout
stauts: 2
end
scenario 3 - exit code 2 with unsafe
stderr
output
stdout
stauts: 2
end
Proposed Change / Implementation
I haven't had much time yet to check the internals and think how this could look, but since status expression is already available in the failed block we could perhaps try to redirect and capture stdout + stderr of each command and then make it available via special variables or expression inside the block.
Perhaps something along the lines of (pseudo code):
import * from "std"
main (args) {
// Option 1 via special variables / expression which is available inside and
// outside the failed block
let output = silent $ echo "stdout" ; >&2 echo "stderr" ; exit 2 $ failed {
echo "Inside failed block"
echo "status: {status}"
echo "stdout: {stdout}"
echo "stderr: {stderr}"
if contains(stdout, "errNoPermission") {
echo "Command returned no permission error."
echo "This likely indicates your session key has expired. Please visit XXX for more information on how to retrieve new or refresh the session key."
}
}
// Option 2 via return values
let stderr, stdout = silent $ echo "stdout" ; >&2 echo "stderr" ; exit 2 $ failed {
echo "Inside failed block"
echo "status: {status}"
echo "stdout: {stdout}"
echo "stderr: {stderr}"
}
echo "status: {status}"
echo "stdout: {stdout}"
echo "stderr: {stderr}"
}
Thanks.
Related PRs, Issues
- This issue looks somewhat related, note sure if we should merge or mark mine as duplicate - https://github.com/amber-lang/amber/issues/287
- https://github.com/amber-lang/amber/issues/296
Links
- Docs - https://docs.amber-lang.com/basic_syntax/commands
tldr - you want a way to merge stdout and stderr and read them both from one fd
right?
@b1ek Not necessarily.
I would like to see / solve two things:
- Make both stdout and stderr available - today it appears only stdout is available, unless you redirect stderr to stdout as part of the actual command (or use some hack to redirect both FDs to a temporary file and then read then read the content at the end, this way it will also be available in case the command exited with non zero). It doesn't need to be merged, in fact, I would even prefer to make it available separately.
- Make both of those values available also on the failure scenario when command exists with non-zero status code - ideally inside + outside the
failedblock.
Per my understanding neither of that is possible directly today without hacks / workaround such as the one mentioned above (merging FDs as part of the actual command or redirecting both to a file so it can be read even in case the command failed).
@Kami ah. so the problem is that stderr is not available at all
that should be relatively easy to implement