Sunday, December 19, 2010

Learn Perl in 10 lessons Lesson 5

Executing system commands

Perl provides a function called �system� which canexecute a command or a set of commands directly on the operatingsystem. In fact, Perl passes the command to the operating system, whichexecutes it, and then returns the result back to Perl.

So, for instance, the following Perl script prints the content of the current directory:



What actually happens is that the Unix process which runs the Perlinterpreter forks and the newly created child Unix process executes the�ls� command. When the execution finishes, it returns theexit code of the command back to the Perl interpreter.

If you are familiar with Unix commands exit codes you can test thesuccess of the execution of your command by assigning the return valueof �system� to a variable, and then evaluate this variable.For instance:

$lsExecutedSuccessfully = system(�ls�);

Here, if �ls� executes successfully, the variable$lsExecutedSuccessfully receives the value 0. This value corresponds tothe successful exit code of the command �ls�.
Executing system commands and capturing the output

Sometimes, when you run a Linux command from your Perl script you'remore interested in what it writes on the screen than in its exit code.For instance, when you execute �ls� you're more likely tobe interested in the list of files being printed on the screen than inthe value 0 returned by �system�.

To achieve this, you can use evaluated quotes �`�instead of �system�. Not only does it executes the command,but it also returns what the commands writes in its standard output:

@files = `ls`;

In this example, the listing of the files returned by�ls� does not appear on the screen. Instead, it gets storedin the @files array.
Changing the working directory

In the shell you would type "cd /home" to change the workingdirectory to /home. You could write the following in your Perl script:

system("cd /home");

But it would have no effect. In fact, since the system call forksfrom the process used by the interpreter, it doesn't change the workingdirectory of your script. Instead, you can use a Perl function called"chdir":

chdir "/home";
Interacting with the filesystem

Perl provides a lot of functions to interact with the files anddirectories of your filesystem. Here are some of these handy functions:

"chmod" changes the permissions of a file or a list of files andreturns the number of files that were changed. The first argument mustbe the numerical mode. Examples:

chmod 0777, "/home/clem/";

chmod 0777, @myFiles;

"symlink" creates a symbolic link. It is the equivalent of "ln -s".The first argument is the file name, the second argument is the linkname. Example:

symlink "/home/clem/", "/usr/bin/program";

"mkdir" creates a directory. The first argument is the name of thedirectory and the second argument is the octal mode which defines thepermissions for that directory. For example:

mkdir "/home/clem/perl_programs", 0664;

"rename" is the equivalent of "mv" in Unix. It renames or moves a file. Example:

rename "/home/clem/", "/home/clem/program";

"rmdir" deletes a directory, but only if it is empty. Example:

rmdir "/home/clem/perl_programs";

"stat" returns a 13-element array which represent the properties of a file. The elements of the array are :

0: $dev, 1: $ino, 2: $mode, 3: $nlink, 4: $uid, 5: $gid, 6: $rdev,7: $size, 8: $atime, 9: $mtime, 10: $ctime, 11: $blksize, 12: $blocks


stat "/home/clem/";

"unlink" deletes a file or a list of files. Example:

unlink "/home/clem/";
Perl Script Exercise: Netswitch

In this exercise, we want to be able to switch between networks. Wedefined network configuration files in a directory called "networks".

For instance, here is the content of ./networks/home:




And here is the content of ./networks/work:




The following Perl script takes a network name as its command lineargument, opens the file with the same name from ./networks and setsthe network interface with the data taken from the content of that file:


#default values







$proxy_port = "none";

#gather information from the network file

$network = $1;

$networkFile = "./networks/$network";

open (NETWORK, "$networkFile") or die "$networkFile not found or not readable\n";

while ($line = ) {

chomp $line;

($variable, $value) = split /=/, $line;

if ($variable eq "interface") $interface = $value;

elsif ($variable eq "type") $type = $value;

elsif ($variable eq "address") $address = $value;

elsif ($variable eq "gateway") $gateway = $value;

elsif ($variable eq "dns") $dns = $value;

elsif ($variable eq "proxy") $proxy = $value;

elsif ($variable eq "proxy_port") $proxy_port = $value;


#make sure the type and interface are defined

if ($interface eq "none") die "Interface name not defined\n";

if ($type eq "none") die "Network type (dhcp, static) not define\n";

if ($type eq "dhcp") {

print "Network type: dhcp\n";

#just get an IP address and settings from the DHCP Server



elsif ($type eq "static") {

print "Network type: static\n";

#bring the interface up

if ($address eq "none") die ("IP address not defined\n");

system("ifconfig $interface $address up");

if ($gateway ne "none") {

print "Gateway: $gateway\n";

system("route add default gw $gateway");


if ($dns ne "none") {

print "DNS Server: $dns\n";

$strNameServer = "cat "."'"."nameserver $dns"."' > /etc/resolv.conf";




else die "Bad network type : $type. Use dhcp or static.\n";

Try to understand each line of that script. The script doesn't setthe proxy in APT, Firefox...etc. See if you can update the script toadd such functionality. Also, it would be great if the script couldlist the possible networks available when the user types "netswitch-l". As there are many ways to solve a problem, especially in Perl,please post your solutions and ideas. Together you should be able towrite a great network switcher.

You now know all you need to start writing this script, however if you have any questions do not hesitate to ask.

No comments:

Post a Comment