Página 1 de 1

Problema con funcion qx()

NotaPublicado: 2012-06-28 19:48 @866
por magnobalt
Hola, comunidad.

Estoy realizando un script en Perl con agregados de bash, más precisamente con el comando find en este último, que me permite encontrar archivos de distintas extensiones y en un periodo de tiempo, para luego analizarlo en busca de malware.

El problema es que desde la consola al ejecutar el siguiente comando, por ejemplo,
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. find /home/user/www/ -type f \( -iname "*.php" -o  -iname "*.js" \) -mtime -1 -ls
  2.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

lo ejecuta sin problemas y realiza la búsqueda de todos los archivos que tengan la extensión php o js que se hayan modificado en un periodo de un 1 día.

El problema resulta al llevar este comando con la función qx() para luego analizar la salida y trabajarlo con Perl, pues me arroja errores de sintaxis en bash.

Al ejecutar de esta manera, en Perl:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. @files=qx(find /home/ -type f \( -iname "*.php" -o  -iname "*.js"\) -mtime -$t  -ls );
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

tengo el siguiente error sh: Syntax error: "(" unexpected

Entonces pensé en colocar doble barra diagonal:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. @files=qx(find /home/ -type f \( -iname "*.php" -o  -iname "*.js"\) -mtime -$t  -ls | awk '{print  \$8 ":" \$9":" \$11}');     
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

tengo el siguiente error find: expresión no válida; se esperaba encontrar un «)» pero no hay ninguno.


¿Alguna ayuda?

Muchas gracias

Re: Problema con funcion qx()

NotaPublicado: 2012-06-28 20:35 @899
por explorer
El error está en que '\)' está pegado a la comilla doble, por lo que find no lo interpreta como un argumento más.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2.  
  3. my $t = -1;
  4. my @files = qx(find . -type f \\( -iname "*.pl" -o -iname "*.txt" \\) -mtime $t -ls | awk '{print  \$8 ":" \$9 ":" \$10 ":" \$11}');
  5.  
  6. print "@files";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


De todas maneras, esto es muy ineficiente: estás llamando a dos comandos externos (find y awk) que, perfectamente, podrías hacer con el propio Perl.

Empezando por el find...

Perl viene con un programa que se llama find2perl, que sirve para traducir comandos find en programas Perl (de ahí le viene el nombre :) )

Entonces, si ejecutamos
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. find2perl  find . -type f \( -iname "*.pl" -o -iname "*.txt" \) -mtime -1 -ls
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

nos entrega a la salida estándar un programa así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #! /usr/bin/perl -w
  2.     eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
  3.         if 0; #$running_under_some_shell
  4.  
  5. use strict;
  6. use File::Find ();
  7.  
  8. # Set the variable $File::Find::dont_use_nlink if you're using AFS,
  9. # since AFS cheats.
  10.  
  11. # for the convenience of &wanted calls, including -eval statements:
  12. use vars qw/*name *dir *prune/;
  13. *name   = *File::Find::name;
  14. *dir    = *File::Find::dir;
  15. *prune  = *File::Find::prune;
  16.  
  17. sub wanted;
  18. sub ls ();
  19.  
  20.  
  21. my @rwx = qw(--- --x -w- -wx r-- r-x rw- rwx);
  22. my @moname = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
  23.  
  24. my (%uid, %user);
  25. while (my ($name, $pw, $uid) = getpwent) {
  26.     $user{$uid} = $name unless exists $user{$uid};
  27. }
  28.  
  29. my (%gid, %group);
  30. while (my ($name, $pw, $gid) = getgrent) {
  31.     $group{$gid} = $name unless exists $group{$gid};
  32. }
  33.  
  34.  
  35. # Traverse desired filesystems
  36. File::Find::find({wanted => \&wanted}, 'find', '.');
  37. exit;
  38.  
  39.  
  40. sub wanted {
  41.     my ($dev,$ino,$mode,$nlink,$uid,$gid);
  42.  
  43.     (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
  44.     -f _ &&
  45.     (
  46.         /^.*\.pl\z/si
  47.         ||
  48.         /^.*\.txt\z/si
  49.     ) &&
  50.     (int(-M _) < 1) &&
  51.     ls;
  52. }
  53.  
  54.  
  55. sub sizemm {
  56.     my $rdev = shift;
  57.     sprintf("%3d, %3d", ($rdev >> 8) & 0xff, $rdev & 0xff);
  58. }
  59.  
  60. sub ls () {
  61.     my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
  62.         $atime,$mtime,$ctime,$blksize,$blocks) = lstat(_);
  63.     my $pname = $name;
  64.  
  65.     $blocks
  66.         or $blocks = int(($size + 1023) / 1024);
  67.  
  68.     my $perms = $rwx[$mode & 7];
  69.     $mode >>= 3;
  70.     $perms = $rwx[$mode & 7] . $perms;
  71.     $mode >>= 3;
  72.     $perms = $rwx[$mode & 7] . $perms;
  73.     substr($perms, 2, 1) =~ tr/-x/Ss/ if -u _;
  74.     substr($perms, 5, 1) =~ tr/-x/Ss/ if -g _;
  75.     substr($perms, 8, 1) =~ tr/-x/Tt/ if -k _;
  76.     if    (-f _) { $perms = '-' . $perms; }
  77.     elsif (-d _) { $perms = 'd' . $perms; }
  78.     elsif (-l _) { $perms = 'l' . $perms; $pname .= ' -> ' . readlink($_); }
  79.     elsif (-c _) { $perms = 'c' . $perms; $size = sizemm($rdev); }
  80.     elsif (-b _) { $perms = 'b' . $perms; $size = sizemm($rdev); }
  81.     elsif (-p _) { $perms = 'p' . $perms; }
  82.     elsif (-S _) { $perms = 's' . $perms; }
  83.     else         { $perms = '?' . $perms; }
  84.  
  85.     my $user = $user{$uid} || $uid;
  86.     my $group = $group{$gid} || $gid;
  87.  
  88.     my ($sec,$min,$hour,$mday,$mon,$timeyear) = localtime($mtime);
  89.     if (-M _ > 365.25 / 2) {
  90.         $timeyear += 1900;
  91.     } else {
  92.         $timeyear = sprintf("%02d:%02d", $hour, $min);
  93.     }
  94.  
  95.     printf "%5lu %4ld %-10s %3d %-8s %-8s %8s %s %2d %5s %s\n",
  96.             $ino,
  97.                  $blocks,
  98.                       $perms,
  99.                             $nlink,
  100.                                 $user,
  101.                                      $group,
  102.                                           $size,
  103.                                               $moname[$mon],
  104.                                                  $mday,
  105.                                                      $timeyear,
  106.                                                          $pname;
  107.     1;
  108. }
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

¿Que es enorme para lo que queremos? Pues sí, pero... si tenemos el fuente, ahora podemos modificarlo para nuestro problema en particular, que trata de sacar la fecha y nombre de los archivos.

Solo tenemos que modificar el último printf() de la función ls() para que saque los campos que nos interesan, y ya está. Y nos ahorramos el llamar a awk.

Seguimos con awk... ya hemos dicho que no tenemos que hacer nada porque modificando el printf() lo tenemos resuelto, pero en otras ocasiones sí que nos vemos obligado a usarlo.

Bueno, en Perl, todo lo que hace awk se puede imitar bastante bien. En nuestro caso, un comando como

awk '{print \$8 ":" \$9 ":" \$10 ":" \$11}'

lo podemos escribir como

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my @campos = split;
  2. print join(":", @campos[8..11]), "\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

y nos ahorramos una llamada externa a awk, que siempre es algo muy costoso desde el punto de vista del ordenador.

Re: Problema con funcion qx()

NotaPublicado: 2012-06-29 06:50 @326
por magnobalt
Gracias, explorer.

Voy a tener en cuenta la llamada al awk y optimizar el código.

Saludos