Workshop in Computational Bioskills - Spring 2008
Part 3 - Process Control
Part 4 - Signals
Option I:
Use the "system" command:
(See perldoc -f system)
The system command allow us to run other commands through a shell. system("date"); But not in a very convenient way. We can't send input to the new program, nor can we get its output.
One good thing about system though, is that it returns the exit value of the command.
Basically system opens a new process and waits for it to execute the command and return.
If given a scalar as an
input, system uses the shell to parse it.
system "grep 'bioskill' /etc/passwd"; # using shell
But it can also be given a
list of ($command, @arguments). In that case, the command is
called directly.
system
"grep","bioskill","/etc/passwd"; # avoiding shell
Option
II: Use the "exec" command:
(See perldoc -f exec)
exec is quite like system, only that it never returns, as the new
command replaces the current one.
Option
III: Use backtics (`):
(See perldoc perlop)
Using backtics is a nice and
simple way of executing commands. In scalar context, the output
of the program is returned.
$now
= "the time is now ".`date`;
In array context, the output
is returned, one line per cell.
@list
= `who`;
or
foreach
$_ (`who`) {
($who,$where,$when)
= /(\S+)\s+(\S+)\s+(.*)/;
print
"$who on $where at $when\n";
}
o The
problem:
How to get the return
value of our command ?
Option
IV: Use processes as File-Handles:
(See perldoc -f open or perldoc perlopentut)
A nice way is to open a
process as a file handle.
-
Read input from "who" command
open(I,
"who|");
while(<I>)
{
print;
}
-
Example: Write output to "lpr" command
open(LPR,"|lpr");
print
LPR @rockreport;
close(LPR);
Option V: Use "fork":
The fork command creates a clone of the current process. This clone (called the child, while the original is called the parent) shares the same executable code, variables, and even open files. To distinguish the two processes, the return value from fork is zero for the child, and nonzero for the parent (or undef if the system call fails). The nonzero value received by the parent happens to be the child's process ID.
- An
example of running date with fork:
if
(!defined($kidpid = fork())) {
# fork returned undef, so failed
die
"cannot fork: $!";
}
elsif ($kidpid == 0) {
# fork returned 0, so this branch is the child
exec("date");
# if the exec fails, fall through to the next statement
die
"can't exec date: $!";
}
else {
# fork returned neither 0 nor undef,
# so this branch is the parent
waitpid($kidpid,
0);
}
Although tedious, this command gives more options of executing commands ...
A list of
signals:
UNIX>
kill -l
HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR2 SEGV USR2 PIPE ALRM
TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM
PROF WINCH POLL PWR UNUSED RTMIN RTMIN+1 RTMIN+2 RTMIN+3 RTMAX-3
RTMAX-2 RTMAX-1 RTMAX
o sending
a signal
kill
($signal, $pid); #
send $pid signal $signal
o ignore
INT signal
$SIG{INT}
= 'IGNORE';
o restore
it to default
$SIG{INT}
= 'DEFAULT';
o
catching Ctrl-C (INT signal)
$SIG{INT}
= \&got_int;
sub
got_int {
$SIG{INT}
= \&got_int;
print
"got INT signal\n";
}
o sending
an alarm every 2 seconds
$| =
1; # set output
buffer size to 1 char.
$SIG{ALRM}
= \&my_alarm; #
set my_alarm as signal handler
alarm(2); # send alarm in 2 secs.
while(1)
{ # start an endless
loop
print
".";
sleep
1;
}
sub
my_alarm {
$SIG{ALRM}
= \&my_alarm;
print
"ALARM\n";
alarm(2); # send alarm in 2 secs.
}