exiting forth with EXIT_FAILURE equivalent - gforth

Apologies if this has already been asked, but for some reason I can't seem to find this anywhere. I want to write a word that write some information to stderr, then exits forth, but sets the exit code before doing so.
I know I can use bye to exit forth, but I can't find any mention anywhere of an analagy for exit(EXIT_FAILURE) in c.
i.e.
: word
s" error" stderr write-file exit_failure ;
~ $ gforth -e 'word'
error
~ $ echo $?
1
how am I supposed to do this?

You can use the word (bye) to return an exit code. That will go around the normal processing that is in the regular bye, but it will get your exit code out.
So, if you want to return 27 for some reasons
27 (bye)
will get it done

Related

Perl: After a successful system call, "or die" command still ends script

I am using the following line to make a simple system call which works:
system ("mkdir -p Purged") or die "Failed to mkdir." ;
Executing the script does make the system call and I can find a directory called Purged, but the error message is still printed and the script dies. What is wrong with my syntax?
system returns the exit status of the command it calls. In shell, zero exit status means success. You have to invert the logic:
0 == system qw(mkdir -p Purged) or die "Failed to create the dir\n";
That would be a little confusing, wouldn't? - Leonardo Herrera on Ikegami's answer
Yes, it is confusing that the system command inverts true and false in Perl, and creates fun logic like this:
if ( system qw($command) ) {
die qq(Aw... If failed);
}
else {
say qq(Hooray! It worked!);
}
But, it's understandable why the system command does this. In Unix, an exit status of zero means the program worked, and a non-zero status could give you information why your system call failed. Maybe the program you were calling doesn't exist. Maybe the program sort of worked as expected. For example, grep returns an exit code of 1 when grep works, but there were no matching lines. You might want to distinguish when grep returns zero, one, or a return code greater than one. (Yes, I know it's silly to use a system call to grep in a Perl program, but that's the first example I could think of).
To prevent casual confusion, I create a variable that holds the exit status of my system command instead of testing the output of system directly:
my $error = system qw($command);
if ($error) {
die qq(Aw... It failed);
}
else {
say qq(Hooray! It worked!);
}
It's completely unnecessary, and people who work with Perl should know that system reverses Perl's definition of true and false, but if I hadn't had my coffee in the morning, I may miss it as I go over someone else's code. Doing this little step just makes the program look a bit more logical.
The Perldoc of system give you code that allows you to test the output of your system command to see exactly what happened. (If there was an error, or a system interrupt signal killed the system call). It's nice to know if you need to interrogate your system return value to figure out what went wrong.
system returns 0 on success, so you want and rather than or.
See also: use autodie qw( system );
To add what hasn't been mentioned but what comes with it and can quietly mess things up.
The system's return of 'zero-or-not' only tells whether the command itself executed successfully, by shell or execvp; the 0 does not mean that the command succeeded in what it was doing.†
In case of non-zero return you need to unpack $? for more information;† see system for how to do this. For one, the command's actual exit code is $? >> 8, what the executed program was designed to communicate at its exit.
Altogether you may want to do something to the effect of
sub run_system {
my ($cmd, #other_agrs) = #_; # may do more via #other_args
my ($cmdref, $sys_ret) = (ref $cmd, 0); # LIST or scalar invocation?
if ($cmdref eq 'ARRAY') {
$sys_ret = system(#$cmd);
}
elsif (not $cmdref) {
$sys_ret = system($cmd);
}
else { Carp::carp "Invocation error, got $cmdref" }
return 1 if $sys_ret == 0;
# Still here? The rest is error handling.
# (Or handling of particular non-zero returns; see text footnote)
Carp::carp "Trouble with 'system($cmd)': $?";
print "Got exit " . ($? >> 8) . " from $cmd\n";
return 0; # or Carp::croak (but then design changes)
}
This can be done merely as system == 0 or do { ... }; or such right in the code, but this way there's a little library, where we can refine error handling more easily, eventually decide to switch to a module to manage external commands, etc. Also, being a user-level facility now it makes sense that it returns true on success (we aren't changing system's design).
Additionally in this case, mkdir -p is meant to be quiet and it may not say anything when it cannot do its thing, in some cases. This is by design of course, but one should be aware of it.
† A program may return whatever it wants; nothing requires of it to return zero if it succeeded (completed without error) and it does not have to follow any conventions; what it returns is entirely up to its design.
Typical Unix programs generally follow the convention of returning non-zero only if there were problems, but some do return non-zero values merely to indicate a particular condition. See for example here and here.
One example: for at least some versions, zip returns non-zero (12) when it "has nothing to do" (nothing to update in a package for example), even though it completes successfully; so we get 3072 from system in that case (when that 12 is packed into high bits of a number which is the return code). This is documented on its man page.
A zero return, though, normally does imply a successful operation, what is the main point here.
Simplest
system ("mkdir -p Purged") && die "Failed to mkdir.";
The system command passes through the exit code of the program that it ran. It doesn't judge or interpret it. Raku, on the other hand, does interpret it and you have to fight the language to get around it. And, remember that Perl's system is basically C's system (and many things in Perl are just what C's version does).
You need to compare this to the value you expected based on your knowledge of that particular command's behavior, as shown in the system docs:
#args = ("command", "arg1", "arg2");
system(#args) == 0
or die "system #args failed: $?"
Usually, well made unix programs use 0 to indicate success and non-zero for everything else. That's a good rule of thumb, but it's a convention rather than a requirement. Some programs return non-zero values to indicate other sorts of success. system knows none of that. Not only that, many programmers have no idea what an exit code should be, and I've often had to deal with someone's reinvented idea of what that should be (and I've probably done that myself at some point).
There's been a growing trend of "trust and don't verify", which I think is the new generation of programmers not having systems and shell programming backgrounds. And, even then, there's how the world should be and how it actually is. Remember, your goal as the programmer is to know what happened and why, even if the world is messy.
Here are a few interesting links:
Well Behaved Non-Zero Exit Codes?
Non-zero exit status for clean exit
Are there any standard exit status codes in Linux?
I like this statement from Frederick the best, though:
More realistically, 0 means success or maybe failure, 1 means general failure or maybe success, 2 means general failure if 1 and 0 are both used for success, but maybe success as well.
Consider grep. Here's a file to search:
$ cat original.txt
This is the original
This is from append.txt
This is from append.txt
This is from append.txt
Search for something that exists:
$ grep original original.txt
This is the original
The exit code is 0 ($? on the shell, but Perl's $? is more complicated). That's what you expect by convention. You found something and there were no errors:
$ echo $?
0
But now search for something that doesn't exist. You don't find something but there were no errors:
$ grep foo original.txt
Now the exit code is 1, because that's what grep does:
$ echo $?
1
This is non-zero but not an error. You called grep correctly and it produced the correct and expected output.
It's not up to system to judge those exit values. It passes through that exit code and lets you interpret them.
Now, we get lazy and assume that 0 means that it worked. We do that because many people are used to seeing it and it works most of the time. But, "works most if the time" is different than "won't bite me in the ass". Compare the result to system to exactly what you will accept as success:
my $expected = 0;
system('...') == $expected or die ...
If the task's definition of success is that grep finds matching lines, that code works fine because the exit code in that case happens to be zero. But, that accidentally works because two different ideas happen to align at that one point.
But, what you accept as success is not the same thing as the exit code. Consider that grep example. So far you know that both 0 and 1 are normal operation. Both of those mean that grep did not encounter an error. That's different than calling grep incorrectly and getting a different exit value:
$ grep -X foo original.txt
grep: original.txt: Undefined error: 0
$ echo $?
2
That 2 is conventionally used to signal that you called the program incorrectly. For example, you are using switches that exist on one implementation of a tool that don't exist on another (there are other things than line and gnu, but less so).
You might end up with something like this:
my %acceptable = map { $_ => 1 } qw(0 1);
my $rc = system(...);
die ... unless exists $acceptable{$rc};
And, the die can pass through that exit code (see it's method for choosing a value):
$ perl -e 'system( "grep -X foo original.txt" ) == 0 or die'
grep: original.txt: Undefined error: 0
Died at -e line 1.
$ echo $?
2
Sure, that's not as pretty as the single statement, but pretty shouldn't trump correct.
But that's not even good enough. My linux version of grep says it will exit with 0 on error in certain conditions:
Normally the exit status is 0 if a line is selected, 1 if no lines were selected, and 2 if an error occurred. However, if the -q or --quiet or --silent is used and a line is selected, the exit status is 0 even if an error occurred.
Going a step further, there's a list of conventional exit codes in sysexits.h that signal very particular conditions. For example, that exit code of 2 gets the symbol EX_USAGE and indicates a problem with the way the command was formed.
When I'm writing system code, I'm hard core on proper exit codes so other programs can know what happened without parsing error output. The die called by the user without a failure in a system will probably return 255. That's not very useful for other things to figure out what went wrong.
A one-line solution:
system("if printf '' > tmp.txt; then exit 1; else exit 0; fi ;") or die("unable to clobber tmp.txt");

ZSH Magic for certain exit-status situations

Hey I thought about writing a function that prompts me in certain situations (perl had a bad exit status and the warning it prints starts with "Could not find * in #INC) with maybe re-running the command.
Do you think this is feasable?
I have found that TRAPZERR function. but i don't even get the name of the last command in there, only the last argument, so one concrete point would be: how can I get the command-name out of it? !!:0 doesn't work.
Next thing is: i think i might have to do some tricks with preexec to catch the first line of the stderr (if that doesn't work that's not a big problem, but it would be interesting anyway), I thought about appending an 2> to a pipe or something but I'm not sure how to get that pipe constructed in the first place. But as stated above, this is a minor issue.
But really, if you think: No this task is impossible! Please tell me so (although I would be interested why).
From the one answer i got until now I think i can narrow down the problem a little:
Is it possible to wrap a MULTIOS redirection around a perl script? ( I thought about some special kind of exec, but came up with none that worked)
Here's a start.
preexec() {
lastcommand=$1
exec 3>&1 4>&2
exec 2> >(tee /tmp/output 1>&4)
}
precmd() {
read line </tmp/output
case "$line" in
"Can't locate"*)
echo "Perl module missing running $lastcommand"
;;
esac
}
But maybe you want to do something at the language level like How can I hook into Perl's use/require so I can throw an exception?

How to terminate a program in Perl - exit or die?

I am using syntax checking to see whether my Perl script is being used in the correct way. If the syntax is not correct, I display a message saying what the correct syntax is, and then end the execution of the program.
Between:
print "Please use the following syntax: ...";
exit 1;
and:
die("Please use the following syntax: ...");
Which one should I use? I know die would have been the answer if exception handling was in place, but that is not the case.
Which one is the better choice for program termination without exception handling? Please also say why.
It depends on what you want to have happen with STDERR and STDOUT. I prefer to send error and warning type messages to STDERR so that when someone is trying to redirect output to a file they still see the error messages; However, there are times though when STDOUT is used to communicate status to the user so he or she can tail -f or paginate it, and at those times writing to STDERR causes them pain (they have to redirect STDERR back into STDOUT with 2>&1, and not everyone knows how to do that). So which to use, die or print and exit, depends heavily on what type of program you are writing.
There are other benefits/drawbacks to using die:
You can trap die with an eval, but not exit
You can run code when the program calls die by installing a signal handler for the __DIE__ signal
You can easily override the die function
Each of those has times where it is handy to be able to do them, and times when it is a pain that they can be done.
print prints to STDOUT but die prints to STDERR
exit 1 exits with exit status of 1 but die exits with exit current value of errno that is $!
Hence die is the preferred way as its simpler and shorter.
It is best to follow existing practice ("rule of least surprise"): exit with 2 on a fatal error such as a syntax error.

In Perl, how do I determine if there's a standard input present?

I've got a script that grabs standard input:
&process_input
sub process_input {
while(<STDIN>) {
$log_data .= $_;
}
}
When I run the script:
myscript.pl -param1=a -param2=b
I get stuck in this subroutine. Everything runs OK if I do:
echo "" | myscript.pl -param1=a -param2=b
How do I determine if I even have a standard input?
I would have thought that while(<STDIN>) would return false and not run, but I'm guessing it's actually waiting for you to type something in that why it's 'stuck'.
You want to check where your STDIN (STanDard INput) is coming from: another application or a terminal. In your case, it's the second option, causing a read operation to stall the process until the user inputs something. For a solution, see How can I tell if STDIN is connected to a terminal in Perl?.
if (-t STDIN) {
# input attached to terminal and will probably ask user
} else {
# input from other process
}
There's also IO::Interactive that might do better/more reliable checking.
The statement <STDIN> does not return until you press Enter on the console. If you want to get around this, I believe that you can use IO::Handle to wrap STDIN, and call $stdin->blocking(0) to enable non-blocking I/O.
That's normal. Standard usage for Unix tools is to use STDIN if no input file is given as an argument. Try cat, less, grep, etc. It's up to the caller to provide input, if only
tool < /dev/null
I strongly advise against trying to determine if "input" is available as it will introduce problems no matter how you achieve this. Specifically, avoid -t since it's problematic to fake a terminal when needed. Instead, rely on a more conventional interface.
If you want to make it possible to pass no input to your tool, it's weird that you'd be using STDIN in the first place. One would normally use an optional argument.
tool --foo file
tool --foo <( echo "" )
Another option would be to request that the user tells you when there is no input.
tool --batch
In order to help you with the design problems of your interface, it would really help to know what your tool does.
Your program will continue when the user types Ctrl + D, the end-of-file character.

How do I check the exit code in Test::More?

According to Test::More documentation, it will exit with certain exit codes depending on the out come of your tests.
My question is, how do I check these exit codes?
ps. I am trying to build a harness myself. Is there a simple harness I can use?
ps2. Test::Harness did the trick for me. In particular execute_tests function. This function returns all the statistics I want. Thank you everyone who gave useful links.
Any decent harness program (such as prove) will do that for you, there is absolutely no reason for you to do that yourself.
It's a process return code. If running under some Unix variant's shell, you can usually retrieve it as $?. (which probably makes your question more about bash than perl)
Common idioms:
perl your_file.t
if [[ $? -gt 10 ]]; then
echo "Wow, that's a lot of failures"
elif [[ $? -gt 0 ]]; then
echo "Tests failed"
else
echo "Success!"
fi
Alternately, if you're only interested in success/failure:
perl your_file.t || echo "Something bad happened."
If you're calling your test program from Perl, then the hard (and traditional) way involves doing dark and horrid bit-shifts to $?. You can read about that in the system function documentation if you really want to see how to do it.
The nice way involves using a module which gives you a system style function that processes return values for you:
use IPC::System::Simple qw(systemx EXIT_ANY);
my $exit_value = systemx( EXIT_ANY, 'mytest.t' );
The EXIT_ANY symbol allows your script to return any exit value, which we can then capture. If you just want to make sure that your scripts are passing (ie, returning a zero exit status), and halt as soon as any fail, that's IPC::System::Simple's default behaviour:
use IPC::System::Simple qw(systemx);
systemx( 'mytest.t' ); # Run this command successfully or die.
In all the above examples, you can ask for a replacement system command rather than systemx if you're happy for the possibility of the shell getting involved. See the IPC::System::Simple documentation for more details.
There are other modules that may allow you to easily run a command and capture its exit value. TIMTOWTDI.
Having said that, all the good harnesses should check return values for you, so it's only if you're writing our own testing testers that you should need to look at this yourself.
All the best,
Paul
Disclosure: I wrote IPC::System::Simple, and so may have some positive bias toward it.