• Publicidad

Buscar y sustituir cadenas en un fichero

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Buscar y sustituir cadenas en un fichero

Notapor rucar » 2008-10-09 18:14 @801

Hola a todos, soy nuevo en este foro y sobre todo en Perl.
Estoy leyendo a marchas forzadas porque me corre mucha prisa realizar un script, pero voy a trompicones y me atraganto.

Estoy intentando modificar un fichero ldif para la entrada masiva de usuarios en LDAP. El contenido del mismo podría ser como el siguiente

Código: Seleccionar todo
dn: uid=jperez,ou=People,dc=ejemplo,dc=com
uid: jperez
objectclass: account
objectclass: top
uidnumber: 512
gidnumber: 300
homedirectory: /home/jperez
userpassword: jperez

dn: uid=domingo,ou=People,dc=ejemplo,dc=com
uid: domingo
objectclass: account
objectclass: top
uidnumber: 512
gidnumber: 300
homedirectory: /home/domingo
userpassword: domingo

dn: uid=pepe,ou=People,dc=ejemplo,dc=com
uid: pepe
objectclass: account
objectclass: top
uidnumber: 512
gidnumber: 300
homedirectory: /home/pepe
userpassword: pepe


Tiene varios bloques iguales y tengo que encontrar solamente las líneas que contiene la cadena "userpassword" y después recoger el nombre que viene a continuación de los dos puntos (:) y pasarle otra función que me sustituya dicho nombre por el mismo codificado, algo que he encontrado como lo siguiente:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
$claro=$ARGV[0];
chomp $claro;
$salt = join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
printf "%s\n", crypt("$claro", "$salt");
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4


Sé que con grep() me devuelve las líneas que contiene dicha cadena.

¿Me trata cada una de ellas con un "foreach" para la sustitución individual de cada línea y nombre? ¿Cómo separo el trozo de cadena que me hace falta? ¿Cómo abro el fichero?

¿Podéis ayudarme con el código? Muchas gracias de antemano.
rucar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2008-10-09 17:42 @779

Publicidad

Notapor explorer » 2008-10-09 22:11 @966

Bienvenido a los foros de Perl en Español, rucar.

Esta es una forma de resolver el tema:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
        1 #!/usr/bin/perl
        2 use strict;
        3 use warnings;
        4 use diagnostics;
        5
        6 my @salto = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
        7
        8 my $linea;
        9 my $usuario;
       10 my $salto;
       11
       12 open(FICHERO,"<ldif.txt") or die "ERROR: No puedo abrirlo: $!\n";
       13
       14 while  ($linea   = <FICHERO>) {
       15     if ($linea   =~ m/^userpassword: (\w+)/) {
       16         $salto   = join('', @salto[rand @salto, rand @salto]);
       17         $usuario = crypt($1, $salto);
       18         print "userpassword: $usuario\n";
       19     }
       20     else {
       21         print $linea;
       22     }
       23 }
       24
       25 close(FICHERO);
       26
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

En resumen:
* De las líneas 2 a 4 ajustamos unas opciones que nos ayudarán a identificar errores de programación
* La línea 6 declara y define los caracteres de salto, del nombre de usuario, codificado
* De la 8 a la 10, declaramos unas variables
* En la línea 12 abrimos el fichero de entrada
* El bucle de la línea 14 a la 23 se repite por cada línea del fichero de entrada
* 15: Si la $linea empieza (^) por 'userpassword: ' seguido de una palabra (conjunto de una o más (+) caracteres alfanuméricos (\w)), entonces guarda esa palabra en la variable $1 (por efecto de los paréntesis de captura)
* En la 16 sacamos el $salto (dos caracteres al azar extraídos desde @salto)
* En la 17 codificamos el nombre del usuario (que estaba en $1) con el $salto
* y en la 18 sacamos la nueva línea modificada
* En la 21, sacamos la línea tal cual en caso de no ser la que nos interesa modificar
* 25: cerramos y nos vamos

Si queremos guardar la salida en un fichero debemos hacer otro open(), otro close() y modificar los print para redirigir la salida hacia el fichero de salida.

Y ya está. Pero se puede hacer de otras diez formas distintas...

Por ejemplo, esta otra:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -p
my @salto = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
s/^(userpassword: )(\w+)/$1 . crypt($2, join('', @salto[rand @salto, rand @salto]))/e;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Con
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
./ldif.pl ldif.txt
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
sale:
Código: Seleccionar todo
dn: uid=jperez,ou=People,dc=ejemplo,dc=com
uid: jperez
objectclass: account
objectclass: top
uidnumber: 512
gidnumber: 300
homedirectory: /home/jperez
userpassword: uF6YatSuvV/ls

dn: uid=domingo,ou=People,dc=ejemplo,dc=com
uid: domingo
objectclass: account
objectclass: top
uidnumber: 512
gidnumber: 300
homedirectory: /home/domingo
userpassword: 8KSR4bWoW0HHw

dn: uid=pepe,ou=People,dc=ejemplo,dc=com
uid: pepe
objectclass: account
objectclass: top
uidnumber: 512
gidnumber: 300
homedirectory: /home/pepe
userpassword: /pi6xlVZDBNKg
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor rucar » 2008-10-10 06:30 @313

Muchas gracias, explorer,

Me sirve de lujo, era lo que estaba buscando. He elegido la segunda opción que me planteas, lanzando el perl sobre el fichero de texto.

Muchas gracias.
rucar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2008-10-09 17:42 @779

Notapor explorer » 2008-10-10 08:12 @383

Bien. Ahora tienes como deberes el que expliques aquí cómo funciona la segunda solución y aportar una tercera.

Pero sin prisas...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor rucar » 2008-10-13 18:11 @799

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -p
my @salto = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
s/^(userpassword: )(\w+)/$1 . crypt($2, join('', @salto[rand @salto, rand @salto]))/e;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Te paso a responder, pues me ha picado el tema y he echado un vistazo a algunos tutoriales, aunque hay cosas que todavía no comprendo muy bien.

La primera línea declara y asigna valores a una variable tipo array "my @salto", con distintos elementos como punto (.), barra (/), y rango de números y letras mayúsculas y minúsculas...

En la segunda línea sustituye (s) lo que hay entre los delimitadores ///, es decir, la línea que comienza (^) con "userpassword:" seguido de uno o más caracteres alfabéticos "\w+" (de esto no estoy muy seguro), y lo sustituye por la concatenación del contenido de la variable $1 que fue asignado por los dos primeros "()", más el encriptado del contenido de la variable $2, asignado por los segundos "()".

La función crypt() usa como parámetros crypt(contraseña, clave). La contraseña es la cadena pasada, en este caso $2. Y la clave es la unión por la función join() de dos cadenas.

En esto último es donde me pierdo y no sé exactamente lo que hace la función random() con el array: @salto[rand @salto, rand @salto].

Tampoco sé lo que hace el comando o argumento /e.

¿Podrías explicármelo?

Muchas gracias.
rucar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2008-10-09 17:42 @779

Notapor rucar » 2008-10-13 18:38 @818

Sigo teniendo algún problemilla con script.

Si la cadena en lugar de ser: "userpassword: domingo", es: "userpassword: domingo.lopez", solo me encripta la parte que está antes del punto y me respeta lo otro.

Además el fichero original me lo deja sin cambiar, a pesar de ejecutar correctamente el código.

También se me olvido preguntar antes que significa el argumento "-p" de la llamada al compilador "#!/usr/bin/perl -p"
rucar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2008-10-09 17:42 @779

Notapor explorer » 2008-10-13 18:42 @820

/e le indica a la expresión regular que la segunda parte es un trozo de código Perl que debe ejecutar, y su salida será la que sustituya a la primera parte de la exp. reg.

En cuanto a @salto[rand @salto, rand @salto].

* @salto es un array con varios elementos
* rand @salto obliga a evaluar @salto en contexto escalar, por lo que obtenemos el número de elementos de @salto y ese será el parámetro que le pasamos a rand(). Entonces, rand() nos devolverá un valor entero aleatorio entre 0 (inclusive) y el número de elementos de @salto (excluido)
* Eso lo hacemos dos veces, para obtener dos números
* Usamos esos dos números como índices para extraer dos letras del array @salto. Como son dos valores, estamos extrayendo una lista de elementos. Por eso ponemos una '@' delante
* Las dos letras extraídas son unidas con la ayuda de join().
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor explorer » 2008-10-13 19:01 @834

rucar escribiste:Sigo teniendo algún problemilla con script.

Si la cadena en lugar de ser: "userpassword: domingo", es: "userpassword: domingo.lopez", solo me encripta la parte que está antes del punto y me respeta lo otro.


Cambia (\w+) por (.+). El \w solo es para caracteres alfanuméricos, y el '.' no lo es. Así que ponemos un comodín genérico, y listo. Nos quedamos con todo el resto de la línea.

rucar escribiste:También se me olvido preguntar antes que significa el argumento "-p" de la llamada al compilador "#!/usr/bin/perl -p"

Quiere decir que tiene que abrir el fichero que le indiquemos y hacer un bucle por todas las filas. Por cada fila, aplicará el programa que hemos escrito. Y al final, sacará la linea por la salida estándar. Algo así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
open(FICHERO, "<$ARGV[0]");
while (<FICHERO>) {
    # ... nuestro programa ...

    print;
}
close FICHERO;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


rucar escribiste:Además el fichero original me lo deja sin cambiar, a pesar de ejecutar correctamente el código.
Claro, porque no nos has dicho qué hacer con los cambios... así que de momento solo salen por la salida estándar.

Si quieres que se haga el cambio in-situ, en el propio fichero, hay que agregar la opción -i. Quedaría:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -pi
my @salto = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
s/^(userpassword:\s+)(.+)/$1 . crypt($2, join('', @salto[rand @salto, rand @salto]))/e;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor rucar » 2008-10-14 04:21 @223

Muchas gracias, explorer.

Ahora sí que funciona correctamente. Gracias por la ayuda y por las explicaciones.
rucar
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2008-10-09 17:42 @779


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 2 invitados

cron