Jue Oct 09, 2008 5:14 pm
|
 |
rucar
Perlero Nuevo

|
Registrado: 09 Oct 2008
Mensajes: 5
|
|
| Buscar y sustituir cadenas en un fichero |
|
|
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: |
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:
| Perl: | #!/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"); |
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. |
|
|
|

Jue Oct 09, 2008 9:11 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4082
Ubicación: Valladolid, España
|
|
|
|
|
Bienvenido a los foros de Perl en Español, rucar.
Esta es una forma de resolver el tema:
| Perl: | 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 |
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:
| Perl: | #!/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; | Consale:
| Código: |
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 |
|
|

Vie Oct 10, 2008 5:30 am
|
 |
rucar
Perlero Nuevo

|
Registrado: 09 Oct 2008
Mensajes: 5
|
|
|
|
|
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. |
|
Vie Oct 10, 2008 7:12 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4082
Ubicación: Valladolid, España
|
|
|
|
|
Bien. Ahora tienes como deberes el que expliques aquí cómo funciona la segunda solución y aportar una tercera.
Pero sin prisas... |
|

Lun Oct 13, 2008 5:11 pm
|
 |
rucar
Perlero Nuevo

|
Registrado: 09 Oct 2008
Mensajes: 5
|
|
|
|
|
| Perl: | #!/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; |
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. |
|

Lun Oct 13, 2008 5:38 pm
|
 |
rucar
Perlero Nuevo

|
Registrado: 09 Oct 2008
Mensajes: 5
|
|
|
|
|
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" |
|

Lun Oct 13, 2008 5:42 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4082
Ubicación: Valladolid, España
|
|
|
|
|
/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(). |
|

Lun Oct 13, 2008 6:01 pm
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4082
Ubicación: Valladolid, España
|
|
|
|
|
| rucar escribió: | 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 escribió: | | 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í:
| Perl: | open(FICHERO, "<$ARGV[0]");
while (<FICHERO>) {
# ... nuestro programa ...
print;
}
close FICHERO; |
| rucar escribió: | | 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:
| Perl: | #!/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; |
|
|

Mar Oct 14, 2008 3:21 am
|
 |
rucar
Perlero Nuevo

|
Registrado: 09 Oct 2008
Mensajes: 5
|
|
|
|
|
Muchas gracias, explorer.
Ahora sí que funciona correctamente. Gracias por la ayuda y por las explicaciones. |
|
Powered by phpBB © 2001, 2005 phpBB Group
|