La interacción con programas externos es una característica crítica de Perl, heredada desde la creación del lenguaje en 1987 para tareas de administración del sistema y automatización de rutinas de shell. Perl proporciona varias formas de ejecutar un comando externo: el operador system, las comillas inversas (``) o qx//, la función open con tuberías, y envolturas modulares como IPC::Open3.
El principal problema al lanzar procesos externos es obtener correctamente la salida (stdout y stderr), manejar errores de ejecución, la seguridad de los parámetros (para evitar inyecciones), así como la diferencia entre la ejecución sincrónica y asincrónica.
La solución radica en elegir la forma correcta para la tarea específica. Para comandos simples se utiliza system o comillas inversas, mientras que para casos más complejos se optan por los módulos IPC::*:
Ejemplo de código (lectura de la salida de un comando y manejo de errores):
my $command = 'ls -l /tmp'; my $output = qx{$command}; if ($? == -1) { die "Error al ejecutar: $!"; } elsif ($? & 127) { warn sprintf "El comando terminó con la señal %d", ($? & 127); } else { print "Salida: $output"; }
Características clave:
¿Cuál es la diferencia entre system y exec en Perl?
Respuesta: system lanza un comando en un proceso externo y devuelve el control a Perl después de completarse, mientras que exec reemplaza completamente el proceso actual de Perl con el programa ejecutable, el código Perl posterior no se ejecuta.
Ejemplo:
system('echo Hello'); exec('ls', '-l'); # Listo, el script Perl se reemplaza con ls, después Perl no funciona
¿Se pueden pasar variables de usuario de manera segura a los comandos de shell?
Respuesta: Solo utilizando una lista de argumentos (no cadenas) y evitando la interpolación en el shell. De lo contrario, puede haber una inyección de comandos.
# Seguro: system("ls", "-l", $user_supplied_dir); # Peligroso: system("ls -l $user_supplied_dir");
¿Cómo se puede obtener tanto stdout como stderr de un comando externo?
Respuesta: La forma más segura es usar IPC::Open3 o redirigir stderr a stdout a nivel de shell:
my $out = qx{ls /notexists 2>&1};
o a través de IPC::Open3 (un método más universal y delicado).
Un administrador inserta a través de system("rm -rf $dir") un valor ingresado por el usuario.
Pros:
Contras:
Se utiliza system('rm', '-rf', $dir), se valida $dir, se implementa logging.
Pros:
Contras: