I had to run a shell program exiting with an error from Perl 6, so I've decided to test how it works.
I've made a bash
script producing an error to run it from a Perl 6 program:
$ cat prog.sh
echo "error" >&2
exit 1
Here is how I call it from Perl 6:
put "start";
try {
shell "./prog.sh";
}
put "end";
The output shows that the program exited after running the shell command.
start
error
The spawned command './prog.sh' exited unsuccessfully (exit code: 1)
in block <unit> at b.p6 line 2
If I add a CATCH
block
put "start";
try {
shell "./prog.sh";
CATCH { default {} }
}
put "end";
everything is OK, and the program works to the last line:
start
error
end
So my question: why is it necessary to add the CATCH
block, while try
by itself cannot tackle the error?
Catch the exception using evalIf we wrap a piece of code in an eval block, the eval will capture any exception that might happen within that block, and it will assign the error message to the $@ variable of Perl. The simple way to do this looks like this: (please note, there is a ; after the eval block.)
We use the backticks ( `` ) syntax when we want to capture the output of the shell command. We provide the command between the backticks. If we don't want to capture the output of the shell command, we use the system function, as shown below. The system function will just display the output.
From Perl HowTo, the most common ways to execute external commands from Perl are: my $files = `ls -la` — captures the output of the command in $files. system "touch ~/foo" — if you don't want to capture the command's output. exec "vim ~/foo" — if you don't want to return to the script after executing the command.
exec - Perldoc Browser. The exec function executes a system command and never returns; use system instead of exec if you want it to return. It fails and returns false only if the command does not exist and it is executed directly instead of via your system's command shell (see below).
shell
doesn't throw the Exception
until the sink
.
The try
block with only the shell
in it fully executes without an exception being thrown, returning the last value in the block, which then gets sunk outside the context of the try
, which then throws the Exception
.
You can see this with:
put "start";
try {
shell "./prog.sh";
'something';
}
put "end";
Now the shell gets sunk inside the try
, which gets caught by the implicit CATCH
of the try
. The try
block returns the last value in the block, the 'something', which then gets safely sunk outside the try
.
You can also force the sink
to happen inside the try
:
put "start";
try {
sink shell "./prog.sh"
}
put "end";
Your added CATCH
block is just preventing the try
block from returning the return value from the shell
.
You can re-arrange them and see that this still blows up:
put "start";
try {
CATCH { default {} }
shell "./prog.sh";
}
put "end";
The best, most clear way to handle this IMHO would be to check the return from the shell yourself rather than letting it sink and throw the Exception:
put "start";
if shell "./prog.sh" {
say 'ok'
}
else {
say 'failed'
}
put "end";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With