Exiting a secondary Perl script and returning to the main program - perl

I am running a Perl script to control two other scripts. The user of the main program can call the two secondary scripts with the following line.
do 'Task_A.pl';
The script then runs Task_A.pl but I would like to find a way of then exiting Task_A.pl and return to the main program. If possible I would like to return to the function where I last called the secondary script. I am not sure as to what this is called but I appreciate any input for a possible solution.
This is the whole main program, not much to it at the moment.
my $selecion;
#Looping variables.
my $program_loop = 1;
while ($program_loop == 1)
{
print "Please choose one of the programs listed in the menu.\n";
#Program menu where the user chooses from the presented options.
print "[1] - Script A.\n";
print "[2] - Script B.\n";
print "[3] - Exit program.\n";
my $user_input = <>;
if ($user_input == 1) # <-- Scrip_A.pl
{
do 'Task_A.pl';
}
elsif ($user_input == 2) # <-- Scrip_B.pl
{
do 'Task_B.pl';
}
elsif ($user_input == 3) # <-- Exit Program
{
#The user can choose to exit from the menu.
print "The program will now exit.\n";
exit;
}
}

do does not start another process. If that's what you want, use "system()".
If you want do, then it's probably best to just put everything into a function in the file to be evaluated and call the function at the end of the file.
Use "return" to leave the function and return to next instruction after do.

Related

perl forking the process inside the if statement executes both the blocks

When I fork a new process inside the if condition, surprisingly both if and else block gets executed.
According to the perl fork subroutine documentation when we execute the method, it returns either undef, PID depending on whether the fork failed, succeeded respectively.
Below is the code where both the blocks are getting executed.
if(my $a = fork ) {
say "if block";
} else {
say "else block";
}
output:
if block
else block
Where as if I return those manually only one block gets executed depending on whether i return 0 or 1.
sub a { 1; }
if(my $a = a ) {
say "if block";
} else {
say "else block";
}
output:
if block
Any idea why this is happening?
According to the perl fork subroutine documentation when we execute the method, it returns either undef, PID depending on whether the fork failed, succeeded respectively.
Not quite. It actually says the following:
It returns the child pid to the parent process, 0 to the child process, or undef if the fork is unsuccessful.
So,
In the parent process, fork returns the child's PID, so the parent process outputs if block.
In the child process, fork returns 0, so the child process outputs else block.
By checking the value returned, you can have the parent and child do different things.
It's easier to see what's happening if you also output the process ID (the $$ special variable) with each say statement:
use v5.10;
if( fork ) {
say "$$ (parent): if block";
} else {
say "$$ (child): else block";
}
You'd then see that you get outputs from two different processes:
19997 (parent): if block
20024 (child): else block
Typically, the parent process continues and does its thing while the child process continues and does whatever work you wanted to offload. However, the child inherits the standard filehandles of the parent, so the output goes to the same place. If you don't want that, you can immediately change standard output (and others) in the child (or parent, I guess):
use v5.10;
if( fork ) {
say "$$ (parent): if block";
} else {
say "$$ (child): else block";
open STDOUT, ...
}
If you wanted the current process to turn into something else (so that you still only had one process), look at exec.

Win32::Process::KillProcess not returing proper exitcode

I am writing a function in perl which will kill a process given its PID.
sub ShutPidForWindows()
{
require Win32::Process;
$PID = 1234;
$count = 0;
$ReturnStatus = 0;
$ExitCode = 0 ;
if ($PID == 0)
{
return ($ReturnStatus);
}
Win32::Process::KillProcess($PID, $ExitCode);
print "PID = ".$PID."\n";
print "Return Code = ".$ExitCode."\n";
if ($ExitCode)
{
$ReturnStatus = 1;
}
else
{
$ReturnStatus = 2;
}
return ($ReturnStatus);
}
when this function is executed it always returns 2. Even though the process 1234 does not exists.
The o/p I get is:
PID = 1234
Return Code = 0
Perl Doc says that ExitCode will be populated by the exit code returned by the process. Then ExitCode should be 1.
Am I doing anything wrong?
The problem is that you are using require instead of use to load the module. Sometimes this is OK, but you should always follow the examples in the module's documentation.
You must also always use strict and use warnings at the top of every Perl program you write. This will make it necessary to declare all of your variables, which should be done as close as possible to their first point of use. These measures will reveal many errors that you may otherwise overlook, and is especially important when you are asking others for help with your code.
If you examine $^E after the call to Win32::Process::KillProcess, you might see a value like
The parameter is incorrect
which should tell you that you did something wrong.

Perl Ending loops/code blocks based on user input (!die/exit)

just have a general question that came up while I was playing around with some stuff I coded. I was wondering if there is any way to terminate a specific part of the program based on user feedback (I apologize if I am misusing terminology here) other than die(); since that ends the entire program.
here's the code:
if ($choice eq 'y'){
print "\nHit diagnostics: \n";
{
my $hitList=#hitList;
for (my $i=0; $i<$hitList; $i++){
print $hitList[$i]."\n";
#segmented listout of misses with interrupt
if(($i%4) eq 0){
print "CONTINUE or Q to end\n";
my $next=<>;
chomp($next);
if(lc($next) eq 'q'){
**die "Killing request...\n";**
}
}
}
}
So basically I just want for the user to be able to end the modulus if loop if they decide at some point that they don't actually want to see the entire list but still be able to continue (there is a miss prompt afterwards as well) with the program.
Is the best way to do this just to use a variable as a 'switch' to determine whether or not the hit list should continue? Just wondering if there is a more acceptable/elegant solution.
for my $i (0..$hitList-1) {
...
if (...) {
last;
}
...
}
last

Can't invoke submit queries in PERL CGI

Hey so I am trying to make a simple 'dating website' however I'm struggling with CGI aspect :( Mainly I'm having trouble with forms(I think I'm not too sure what I'm struggling with).
I have this statement
print header, start_html("EngCupid"), h2("EngCupid"), start_form;
if (!param() || param("home")) {
show_welcome();
} elsif (param("browse")) {
browse_page();
} elsif (param("search")) {
search_users();
} elsif (param("username")) {
search_results();
} else {
print "fail";
}
print end_form, end_html;
exit 0;
To Handle the general navigation of the website. However, I'm struggling when it comes to submit buttons etc inside these functions. So my browse_page() function is
sub browse_page {
print h2("Browse Page");
print p;
if (param("next")) {
$hidden_variable = param("x") + 1;
}
param('x', $hidden_variable);
$hidden_variable = 0;
print hidden('x');
print submit("next", "Next");
print submit("home", "Home"), " ", submit("search", "Search Users");
}
Which is supposed to increment a variable that I need to use for further functions every time I press the next key. However, whenever I press the next key it just prints fail as in the form isn't being passed?
Do I need a new form inside each function I am printing? I tried it but it still didn't work. Just a little lost in forms in general.
I am not sure what you are trying to achieve. Maybe the problem is that the x is not being sent back from client to server, maybe you wanted
print hidden('x', param('x'));
Also, why do you set $hidden_variable to 0? After submitting, the script will run again, the old value of the variable will not be accessible anymore.

Perl do...while and last command

I've just encountered some very weird behavior that I really can't explain:
do {
my $qry = $self->getHTMLQuery(undef, $mech->content());
next if (!defined($qry));
push(
#prods,
map { 'http://www.XXXXYYYX.com'.$_->attr('href') }
$qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink')
);
$qry->delete();
$TEST++;
last if ($TEST >= 10);
} while(eval { $mech->follow_link(class => 'jump next') });
print "WHILE ENDED\n";
The code above never prints "WHILE ENDED" even though it does seem to go out of the while loop when $TEST >= 10.
But the following code does print "WHILE ENDED":
do {
my $qry = $self->getHTMLQuery(undef, $mech->content());
next if (!defined($qry));
push(
#prods,
map { 'http://www.XXXXYYYX.com'.$_->attr('href') }
$qry->query('div.prodInfo div.prodInfoBox a.prodLink.GridItemLink')
);
$qry->delete();
$TEST++;
} while(eval { $mech->follow_link(class => 'jump next') } && $TEST <= 10);
print "WHILE ENDED\n";
In both tests, the initial value of $TEST is 0.
Is the behavior of last in do...while different than in for and while {...}?
A do block with a looping modifier doesn't count as a real loop as far as next, last, and redo are concerned. This is mentioned in perlsyn, where you'll find the tip Schwern mentioned about surrounding it with a bare block to make last work. But that won't work with next, because a bare block is only executed once, so next acts like last. To make next work, you can put the bare block inside the do, but then last will act like next.
If you need both next and last to work with a do ... while, the easiest way is to use an infinite loop with the real condition in a continue block. These 2 loops are equivalent, except that the second is a real loop, so it works with next & last:
do { ... } while condition;
while (1) { ... } continue { last unless condition };
From perldoc -f last:
"last" cannot be used to exit a block that returns a value such as
"eval {}", "sub {}" or "do {}"
TLP is right. The standard work around for this (I just hit it myself) is to wrap the do/while in a bare block which, counter-intuitively, does respect loop controls.
{ do {
last;
} while 1; }
The block outside will catch last. If you want to handle next you have to put the bloc inside.
do {{
next;
}} while 1;
The block inside will catch next.
Unfortunately you can't do both.