Perl script returning value in makefile - perl

I have a perl script which returns value "return 1;" or "return 0;".I tried also "exit 1;" and "exit 0;"
In my makefile I have the following code:
ifneq ($(TRG_TYPE),node)
VAR := $(shell perl $(ROOT)/Make/chipdep.pl $(ROOT) $(CHIP) $(NAME) )
ifeq ($(VAR),1)
$(error just a test error. Aborting)
endif
endif
I know that perl script works - I tested it separately, but I never see this error and abort, even when it should be seen!

The value of a shell invocation is the output of the shell command, not its exit code. Make your script print 0 or print 1, or in the general case, do $(shell yourcmd >/dev/null 2>&1; echo $$?) to obtain just the exit code from a shell command.
This seems slightly backwards, though. If your script returns 0 for success and 1 for failure, maybe you should simply run it as the first command of your target; the target will abort if any of its commands fail.

Related

Propagate exit status across pipes

I would like to use a small script to do some cosmetic work to the output of my gcc.
So I use this command:
mygcc foo.c 2>&1 | myscript.pl
Basically my script does things like this:
$error = 0;
while(<>)
{
s/^"(.*)"\s*,\s*line\s*(\d+)\s*:\s*(cc\d+)\s*:/colored("[$3]", 'bold red').colored(" $1", 'red').":".colored("$2", 'yellow')/ge;
s/ \^/colored(" ^", 'yellow')/e;
s/(error:.*$)/colored($1, 'red')/ge;
s/(warning.*$)/colored($1, 'yellow')/ge;
print;
$error = -1;
}
Unfortunately the exit code from gcc is not correctly propagated through the pipe. What I need to do is to get the exit code from gcc and write it back from my script.
Without this, make won't correctly stop the build process in case of an error.
How can I achieve this?
Try using a sub shell:
( mygcc foo.c; echo "gcc returned $?" ) |& myscript.pl
The ( cmd ) construct is used to launch cmd in a sub-shell. Your current shell will fork itself, and the commands will be executed by the child shell. It's an easy way to run multiple commands and have the output fed to a pipe.
The $? variable is the exit status of the last command.
The cmd1 |& cmd1 construct is equivalent to cmd1 2>&1 | cmd2
Take a look at this. You can then use the %ENV variable to access the gcc return status and return that value from your perl script.

Executing Perl script from Tcl

I'm trying to execute a Perl script from Tcl.
I use eval in Tcl, and it executes the Perl script but doesn't execute the other command in my Tcl file.
Tcl:
eval perl perl_script
puts "Command executed"
Result: the Perl script is executed, but not the puts command. Why is this?
In tcl, eval executes its arguments as tcl code, similar to its perl equivalent. But, you do not want this, instead you need to launch the perl interpreter as an external process and ask this interpreter to execute the script passed in its commandline. This is the job of exec in tcl.
exec perl perl_script
Read more about exec # https://www.tcl.tk/man/tcl/TclCmd/exec.htm
UPDATE
exec will throw an error when the command returns a non-zero exit status. You need wrap exec with a catch to continue with non zero exit status. See WORKING WITH NON-ZERO RESULTS
UPDATE 2
The reason why eval perl script_path manages to successfully launch the perl interpreter is tcl's unknown magic. It is likely that you do not have tcl proc named perl. So, tcl calls the "unknown" proc, which tries to handle this exception intelligently by calling exec on its arguments since it finds an executable in $env(PATH). You can try info body unknown to see how this magic actually works.
Try this:
exec sh -c { perl -ape 's/this/that/' tmp.1 > tmp.11 }
It works for me.

Why does jenkins consider this build step as passed?

#!/bin/sh
date;
perl aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.pl
date;
The script does not exist and it should fail.
Exit status (0 is success, everything else is failure) of script is exit status of last command. To fix, store the right exit status in shell variable before doing something else. Example:
#!/bin/sh
date
perl aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.pl
perlexitstatus=$?
date
exit $perlexitstatus
For completeness, two other ways:
#!/bin/sh
set -e # exit on non-zero command exitcode
date
perl aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.pl
date
Above is often a bit inconvenient, because often shell script has commands you don't care about, and don't want the script to fail for them.
#!/bin/sh
set -e # exit on non-zero command exitcode
date
perl aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.pl ||
{ echo "aaaa... Script failed, spam monkey#company.com"; exit 1;}
date
Last one could be written with if-then-fi statement too, if preferred. It provides a way to print custom error message, in case the failing command's message is unclear.
If you set shebang with a shell you could provide -e parameter to make script break on inner command failures:
#!/bin/sh -e
date;
perl aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.pl
date;

Why is the exit code 1 after I run a Perl script successfully?

When I try running my Perl scripts, it executes successfully. Later, when I run this command echo %errorlevel%, it gives me the output as 1. Why?
If Perl returned with errorlevel 1, then either exit(1) was called
>perl -e"exit 1"
>echo %errorlevel%
1
or $? was set to 1 in an END handler
>perl -e"END { $? = 1; }"
>echo %errorlevel%
1
or the program died when $! was 1
>perl -e"$!=1; die;"
Died at -e line 1.
>echo %errorlevel%
1
(This would often indicate a system call failed with "Operation not permitted")
>perl -E"say $!=1"
Operation not permitted
or the program died when $! was 0 and $? was (1 << 8).
>perl -e"$!=0; $?=1<<8; die;"
Died at -e line 1.
>echo %errorlevel%
1
I suppose it's possible for perl to exit with 1 under other circumstances (like problems loading perl itself), but I don't know of any such circumstances.
Something to be aware of, you must interrogate the %ERRORLEVEL% immediately. Every step in a batch script will set or mess with the errorlevel, so if you expect it to stay around, it won't. For instance, if you run a script, then run another command (dir, or echo, etc.) and then check the errolevel, it will be for the command AFTER the script, not for the script itself.

How do I test if a perl command embedded in a bash script returns true?

So, I have a bash script inside of which I'd like to have a conditional which depends on what a perl script returns. The idea behind my code is as follows:
for i in $(ls); do
if $(perl -e "if (\$i =~ /^.*(bleh|blah|bluh)/) {print 'true';}"); then
echo $i;
fi;
done
Currently, this always returns true, and when I tried it with [[]] around the if statement, I got errors. Any ideas anyone?
P.s. I know I can do this with grep, but it's just an example. I'd like to know how to have Bash use Perl output in general
P.p.s I know I can do this in two lines, setting the perl output to a variable and then testing for that variables value, but I'd rather avoid using that extra variable if possible. Seems wasteful.
If you use exit, you can just use an if directly. E.g.
if perl -e "exit 0 if (successful); exit 1"; then
echo $i;
fi;
0 is success, non-zero is failure, and 0 is the default if you don't call exit.
To answer your question, you want perl to exit 1 for failure and exit 0 for success. That being said, you're doing this the wrong way. Really. Also, don't parse the output of ls. You'll cause yourself many headaches.
for file in *; do
if [[ $file = *bl[eau]h ]]; then
echo "$file matches"
fi
done
for file in * ; do
perl -e "shift =~ /^.*(bleh|blah|bluh)/ || exit 1" "$file" && echo $file: true
done
You should never parse the output of ls. You will have, at least, problems with file names containing spaces. Plus, why bother when your shell can glob on its own?
Quoting $file when passing to the perl script avoids problems with spaces in file names (and other special characters). Internally I avoided expanding the bash $file variable so as to not run afoul of quoting problems if the file name contained ", ' or \
Perl seems to (for some reason) always return 0 if you don't exit with an explicit value, which seems weird to me. Since this is the case I test for failure inside the script and return nonzero in that case.
The return value of the previous command is stored in the bash variable $?. You can do something like:
perl someargs script.pl more args
if [ $? == 0 ] ; then
echo true
else
echo false
fi
It's a good question, my advice is: keep it simple and go Posix (avoid Bashisms1) where possible..
so ross$ if perl -e 'exit 0'; then echo Good; else echo Bad; fi
Good
so ross$ if perl -e 'exit 1'; then echo Good; else echo Bad; fi
Bad
1. Sure, the OP was tagged bash, but others may want to know the generic-Posix form.