La función exec

La función exec actúa de manera análoga a system. La diferencia es que el proceso padre es sustituido por el proceso a ejecutar y no se retorna al programa inicial:
exec 'cat -n /etc/passwd';
die "no se pudo ejecutar cat: $!";

La nueva tarea tendrá exactamente el mismo PID que el programa Perl:

pp2@nereida:~/src/perl$ cat exec1.pl
#!/usr/local/bin/perl -w
use strict;
print "$$\n";
exec '/bin/echo $$'
pp2@nereida:~/src/perl$ exec1.pl
8422
8422

Al igual que con system, si se usa la sintáxis con lista de argumentos los metacaracteres shell no son interpretados.

$ cat exec.pl
#!/usr/bin/perl -w
exec '/bin/echo', 'Los argumentos son: ', @ARGV;
Al ejecutar protegemos los argumentos con comillas simples de su interpretación por la shell:
lhp@nereida:~/Lperl/src$ ./exec.pl 'uno' '| ls ' '| who > quien'
Los argumentos son:  uno | ls  | who > quien

Usando exec para Modificar el Entorno de Ejecución de un Programa

Habitualmente usamos el comando de la shell source cuando queremos modificar las variables de entorno comandos desde un fichero de comandos. Suelo usar las funciones exec y system de Perl cuando tengo que crear dinámicamente el programa a ejecutar o tengo que establecer un entorno de trabajo complicado antes de la ejecución de un programa existente. Este es un fragmento de una rutina que envuelve la ejecución desacoplada de un programa para su ejecución en una máquina remota vía SSH:

sub wrapexec {
  my $exec = shift;

  my $dir = getcwd;
  my $program =<< 'EOPROG'; 
chdir "<<$dir>>" || die "Can't change to dir <<$dir>>\n";
%ENV = (<<$ENV>>);
$| = 1;
my $success = !system("<<$exec>>");
warn "GRID::Machine::Core::wrapexec warning!. Execution of '<<$exec>>' returned Status: '$?'.".
     " Success value from system call: '$success'\n" unless $success;
unlink('<<$scriptname>>');
exit(0);
EOPROG

  $exec =~ /^\s*(\S+)/; # mmm.. no options?
  my $execname = $1;
  # Executable can be in any place of the PATH search 
  my $where = `which $execname 2>&1`;

  # skip if program 'which' can't be found otherwise check that $execname exists
  unless ($?) {
    die "Error. Can't find executable for command '$execname'.".
        " Where: '$where'\n" unless  $execname && $where =~ /\S/;
  }

  # name without path
  my ($name) = $execname =~ m{([\w.]+)$};
  $name ||= '';

  my $ENV = "'".(join "',\n  '", %ENV)."'";

  # Create a temp perl script with pattern /tmp/gridmachine_driver_${name}XXXXX
  my $filename = "gridmachine_driver_${name}";
  my $tmp = File::Temp->new( TEMPLATE => $filename.'XXXXX', DIR => File::Spec->tmpdir(), UNLINK => 0);
  my $scriptname = $tmp->filename;

  $program =~ s/<<\$dir>>/$dir/g;
  $program =~ s/<<\$ENV>>/$ENV/g;
  $program =~ s/<<\$exec>>/$exec/g;
  $program =~ s/<<\$scriptname>>/$scriptname/g;

  print $tmp $program;

  close($tmp);
  return $scriptname;
}

Ejercicio 1.2.1  

En http://www.perlmonks.org/ apareció la siguiente pregunta (busque por el tópico calling Unix commands):

Hi, I'm trying write a script that will call a unix comand and either
post the results or parse the results then post them. I thought perhaps
I could accomplish this with exec or system. However, I haven't been
able to figure it out. Any insight would be much appreciated. Thanx
Comente las respuestas. Estudie el módulo Shell y discuta su implementación.

Explique la salida:

pp2@nereida:~/Lbook$ perl -wde 0
main::(-e:1):   0
  DB<1> use Shell qw(echo cat ps cp)
  DB<2> s $foo = echo("howdy", "funny", "world")
main::((eval 7)[/usr/share/perl/5.8/perl5db.pl:628]:3):
3:      $foo = echo("howdy", "funny", "world");
  DB<<3>> s
Shell::AUTOLOAD(/usr/share/perl/5.8/Shell.pm:132):
132:        shift if ref $_[0] && $_[0]->isa( 'Shell' );
  DB<<3>> n
Shell::AUTOLOAD(/usr/share/perl/5.8/Shell.pm:133):
133:        my $cmd = $AUTOLOAD;
  DB<<3>>
Shell::AUTOLOAD(/usr/share/perl/5.8/Shell.pm:134):
134:        $cmd =~ s/^.*:://;
  DB<<3>> p $cmd
Shell::echo
  DB<<4>> n
Shell::AUTOLOAD(/usr/share/perl/5.8/Shell.pm:136):
136:        *$AUTOLOAD = _make_cmd($cmd);
  DB<<4>> n
Shell::AUTOLOAD(/usr/share/perl/5.8/Shell.pm:137):
137:        goto &$AUTOLOAD;
  DB<<4>> x @_
0  'howdy'
1  'funny'
2  'world'
  DB<<5>> c
  DB<6> p $foo
howdy funny world



Subsecciones
Casiano Rodríguez León
2012-02-29