Workshop in Computational Bioskills - Lesson 6

Workshop in Computational Bioskills - Spring 2008

Lesson 5 - Perl V

Part 3 - Process Control
Part 4 - Signals


Part III: Process Management:

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 ...


Part IV: Signals:

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.
}


back to top