Returning an exit code from a shell script that was called from inside a perl script - perl

I have a perl script (verifyCopy.pl) that uses system() to call a shell script (intercp.sh).
From inside the shell script, I have set up several exit's with specific exit codes and I'd like to be able to do different things based on which exit code is returned.
I've tried using $?, I have tried assigning the value of system("./intercp.sh") to a variable then checking the value of that, but the error message is always 0.
Is this because even though something inside the shell script fails, the actual script succeeds in running?
I tried adding a trap in the shell script (ie trap testexit EXIT and testexit() { exit 222; } but that didn't work either.

$? should catch the exit code from your shell script.
$ cat /tmp/test.sh
#!/bin/sh
exit 2
$ perl -E 'system("/tmp/test.sh"); say $?'
512
Remember that $? is encoded in the traditional manner, so $? >> 8 gives the exit code, $? & 0x7F gives the signal, and $? & 0x80 is true if core was dumped. See perlvar for details.
Your problem may be one of several things: maybe your shell script isn't actually exiting with the exit code (maybe you want set -e); maybe you have a signal handle for SIGCHLD eating the exit code; etc. Try testing with the extremely simple shell script above to see if its a problem in your perl script or your shell script.

Related

Equivalent of bash "set -o errexit" for windows cmd.exe batch file?

What's the Windows batch file equivalent of set -o errexit in a bash script?
I have a long batch file filled with different programs to run on Windows command line... basically its an unrolled make file with every compiler command that needs to be run to build an exe in a long sequence of commands.
The problem with this method is that I want it to exit the batch command on the first non-zero return code generate by a command in the script.
As far as I know, Windows batch files have a problem where they don't automatically exit on the first error without adding a lot of repetitive boilerplate code between each command to check for a non-zero return code and to exit the script.
What I'm wondering about, is there an option similar to bash's set -o errexit for Windows cmd.exe? or perhaps a technique that works to eliminate too much boilerplate error checking code... like you set it up once and then it automatically exits if a command returns a non-zero return code without adding a bunch of junk to your script to do this for you.
(I would accept PowerShell option as well instead of cmd.exe, except PowerShell isn't very nice with old-unix-style command flags like: -dontbreak -y ... breaking those commands without adding junk to your command line like quotes or escape characters... not really something I want to mess around with either...)
CMD/Batch
As Ken mentioned in the comments, CMD does not have an equivalent to the bash option -e (or the equivalent -o errexit). You'd have to check the exit status of each command, which is stored in the variable %errorlevel% (equivalent to $? in bash). Something like
if %errorlevel% neq 0 then exit /b %errorlevel%
PowerShell
PowerShell already automatically terminates script execution on errors in most cases. However, there are two error classes in PowerShell: terminating and non-terminating. The latter just displays an error without terminating script execution. The behavior can be controlled via the variable $ErrorActionPreference:
$ErrorActionPreference = 'Stop': terminate on all errors (terminating and non-terminating)
$ErrorActionPreference = 'Continue' (default): terminate on terminating errors, continue on non-terminating errors
$ErrorActionPreference = 'SilentlyContinue': don't terminate on any error
PowerShell also allows more fine-grained error handling via try/catch statements:
try {
# run command here
} catch [System.SomeException] {
# handle exception of a specific type
} catch [System.OtherException] {
# handle exception of a different type
} catch {
# handle all other exceptions
} finally {
# cleanup statements that are run regardless of whether or not
# an exception was thrown
}

perl system() exit code 36096

I am trying to find the meaning of exit code 36096 from the following system() call to ksh script.
$proc_ret = system("/path/to/shellscript.sh");
$proc_ret returns "36096"
I have checked the output of shellscript.sh, It run fine until the another shell script (status.sh) inside shellscript.sh was invoked.
only the first line of that script was invoked, the rest of the script was not get invoked.
here is the content of status.sh
echo "a" > /tmp/a
echo "complete."
echo "b" >> /tmp/a
cat /path/to/mail.txt | mail -s "subject" email#domain
echo "mail complete."
echo "c" >> /tmp/a
I don't know why the script did not continue after the first line. the exit code of system call made to shellscript.sh looks strange to me.
If anyone know the meaning of 36096 then please let me know.
Note that 36096 is 141 * 256. As the system docs tell you, 141 is the exit status of the program. Note again, that an exit status >128 from a shell often means that the child process was killed due to a signal. That signal is obtained by subtracting 128 from the exit status (i.e. look at the low 7 bits).
So the script got signal 13, which is SIGPIPE - write on a pipe with no reader.
It looks as if the mail program could not be started (got the PATH right? Usually cron jobs have a very minimal PATH and you need to set it in your script with something like PATH=$(getconf PATH).)
Then cat pipes into a non-existing reader, and voila, there's your signal.
BTW, that's a useless use of cat, since mail -s subj recipient < /path/to/mail.txt would avoid an expensive fork and pipe.

System call to run pbmtextps: ghostscript

I'm coding a Perl script to generate images with text in them. I'm on a Linux machine. I'm using pbmtextps. When I try to run pbmtextps in Perl with a system call like this
system("pbmtextps -fontsize 24 SampleText > out.pbm");
I get this error message
pbmtextps: failed to run Ghostscript process: rc=-1
However, if I run the exact same pbmtextps command from the command-line outside of Perl, it runs with no errors.
Why does it cause the ghostscript error when I run it from inside a Perl script?
ADDITIONAL INFO: I tried to hack around this by creating a C code called mypbmtextps.c which does the exact same thing with a C system call. That works from the command line. No errors. But then when I call that C program from the Perl script, I get the same ghostscript error.
ANSWER: I solved it. The problem was this line in the PERL script:
$SIG{CHLD} = 'IGNORE';
When I got rid of that (which I need for other things, but not in this script) it worked okay. If anyone knows why that would cause a problem, please add that explanation.
Ah-ha. Well, the SIGCHLD is required for wait(), and so required for perl to be able to retrieve the exit status of the child process created by system(). In particular, system() always returns -1 when SIGCHLD is ignored. $? will also be unavailable with SIGCHLD blocked.
What printed the error message? pbmtextps, or your perl script?
As far as I know, the signal handler for your perl process shouldn't affect the signal handler for the child processes, but this could depend on your version of perl and your OS version. On my Linux Mint 13 with Perl 5.14.2 the inner perl script prints 0, with the outer script printing -1:
perl -e '$SIG{CHLD}= "IGNORE"; print system(q{perl -e "print system(q(/bin/sleep 1))"})'
Is your perl script modifying the environment?
You can test with
system("env > /tmp/env.perl");
and then compare it to the environment form your shell:
env > /tmp/env.shell
diff /tmp/env.shell /tmp/env.perl
Is the perl script also being run from the shell, or is it being run from some other process like cron or apache? (in particular, you should check $PATH)

Ipython script stop on shell error

Does ipython have a setting similar to '-e' in bash that stops the execution of the script if any ipython's shell command returns a non-zero value?
Not directly, no. However, after a !foo shell command, the exit code is stored as the value _exit_code. So your script could check that and throw an error.
For some reason, on my system it multiplies all the exit codes by 256. I'm not at all sure why it's doing that.

How do I exit the command shell after it invokes a Perl script?

If I run a Perl script from a command prompt (c:\windows\system32\cmd.exe), how can I exit the command prompt after the script finishes executing.
I tried system("exit 0") inside the Perl script but that doesn't exit the cmd prompt shell from where the Perl script is running.
I also tried exit; command in the Perl script, but that doesn't work either.
Try to run the Perl script with a command line like this:
perl script.pl & exit
The ampersand will start the second command after the first one has finished. You can also use && to execute the second command only if the first succeeded (error code is 0).
Have you tried cmd.exe /C perl yourscript.pl ?
According to cmd.exe /? /C carries out the command specified by string and then terminates.
If you're starting the command shell just to run the perl script, the answer by Arkaitz Jimenez should work (I voted for it.)
If not, you can create a batch file like runmyscript.bat, with content:
#echo off
perl myscript.pl
exit
The exit will end the shell session (and as a side effect, end the batch script itself.)
You can start the program in a new window using the START Dos command. If you call that with /B then no additional window is created. Then you can call EXIT to close the current window.
Would that do the trick?
You can send a signal to the parent shell from Perl:
kill(9,$PARENT_PID);`
Unfortunately, the getppid() function is not implemented in Perl on windows so you'll have to find out the parent shell PID via some other means. Also, signal #9 might not be the best choice.