Foro de elhacker.net

Programación => Scripting => Mensaje iniciado por: bjeli1980 en 11 Mayo 2010, 14:34 pm



Título: Modificar archivos de texto [batch] [Perl]
Publicado por: bjeli1980 en 11 Mayo 2010, 14:34 pm
Hola,

Me ha surgido un problema que tengo que solucionar y no he dudado en recurrir a este foro, ya que otras veces me habeis echado una mano.

Tengo 16000 archivos de texto en una carpeta en los que les tengo que modificar un solo dato en cada archivo. Los archivos son de esta forma:

LST;1;
costados\koa9\koa9gx70;ko-//-a9-gx7-0 ; ;1;1;0;2278.;325.;18.;0;0;0;0;0;0;0;0;;;;
costados\koa9\koa9gx70;ko-//-a9-gx7-0 ;M;1;1;0;2278.;325.;18.;0;0;0;0;0;0;0;0;;;;
wa;baldas fondo 2, 3, 5 y 6;;0;0;1;1162.;280.;18.;0;0;;;;;;;;;;
plb;puerta común batiente ;;0;0;1;2275.;297.;20.;0;1;2;192;0;0;0;0;0;0;;

En aquellas líneas que aparece la palabra "puerta" o "frente" necesito restarle 1 al valor que está entre el sexto y septimo punto y coma, en este caso 2275.

Por lo que esa línea quedaría así y el resto del archivo estaría igual:
plb;puerta común batiente ;;0;0;1;2274.;297.;20.;0;1;2;192;0;0;0;0;0;0;;

Gracias antes de nada.


Título: Re: Modificar archivos de texto
Publicado por: biribau en 11 Mayo 2010, 20:41 pm
Es fácil si tienes perl
Código
  1. my ($a, $_, $num, $b) = $s =~ m/(([^;]*;){6})([0-9]*)(.*)$/;
  2. $num--;


Título: Re: Modificar archivos de texto
Publicado por: cgvwzq en 11 Mayo 2010, 22:18 pm
Ya lo he modificado y he añadido el bucle que recorre el directorio:

Código
  1. @echo off
  2. setlocal enabledelayedexpansion
  3.  
  4. :main
  5. set /p "dir=Directorio: "
  6. for /f %%x in ('dir /b %dir%') do (call :fichero !dir! %% style="color: #448888;">x)
  7. goto:eof
  8.  
  9. :fichero
  10. set "file=%1\%2"
  11. for /f "tokens=*" %%_ in (%file%) do (
  12.   ((echo %%_ | find "puerta" > nul) || (echo %%_ | find "frente" > nul)) && (call :linea "%%_") || (echo %%_ >> tmp.txt)
  13. )
  14. copy tmp.txt !file! > nul
  15. echo  !file! hecho
  16. del tmp.txt
  17. goto:eof
  18.  
  19. :linea
  20. for /f "delims=; tokens=1-6*" %%a in (%1) do (
  21.   set "num=%%f" & set "num=!num:~0,-1!"
  22.   set /a num-=1
  23.   echo %%a;%%b;%%c;%%d;%%e;!num!.;%%g; >> tmp.txt
  24. )
  25. goto:eof

Al final he copiado el "num=!num:~0,-1!" de Leo, en lugar de "num=!num:.=!". Aunque funciona igual...


Título: Re: Modificar archivos de texto
Publicado por: leogtz en 11 Mayo 2010, 23:26 pm
Algunas preguntas.

Cada archivo solo contiene esto:
Código:
LST;1;
costados\koa9\koa9gx70;ko-//-a9-gx7-0 ; ;1;1;0;2278.;325.;18.;0;0;0;0;0;0;0;0;;;;
costados\koa9\koa9gx70;ko-//-a9-gx7-0 ;M;1;1;0;2278.;325.;18.;0;0;0;0;0;0;0;0;;;;
wa;baldas fondo 2, 3, 5 y 6;;0;0;1;1162.;280.;18.;0;0;;;;;;;;;;
plb;puerta com·n batiente ;;0;0;1;2275.;297.;20.;0;1;2;192;0;0;0;0;0;0;;

Es decir, ¿cada archivo solo contiene 1 vez la línea con "puerta"?

¿Podemos usar aplicaciones externas? (sed para Windows)


Título: Re: Modificar archivos de texto
Publicado por: leogtz en 12 Mayo 2010, 00:20 am
He hecho esto:

Supongamos que nuestro archivo se llama "file.txt", y tiene un contenido igual al que pusiste:
Código
  1. LST;1;
  2. costados\koa9\koa9gx70;ko-//-a9-gx7-0 ; ;1;1;0;2278.;325.;18.;0;0;0;0;0;0;0;0;;;;
  3. costados\koa9\koa9gx70;ko-//-a9-gx7-0 ;M;1;1;0;2278.;325.;18.;0;0;0;0;0;0;0;0;;;;
  4. wa;baldas fondo 2, 3, 5 y 6;;0;0;1;1162.;280.;18.;0;0;;;;;;;;;;
  5. plb;puerta com·n batiente ;;0;0;1;2275.;297.;20.;0;1;2;192;0;0;0;0;0;0;;

La salida que da mi script es:

Código:
LST;1;
costados\koa9\koa9gx70;ko-//-a9-gx7-0 ; ;1;1;0;2278.;325.;18.;0;0;0;0;0;0;0;0;;;;
costados\koa9\koa9gx70;ko-//-a9-gx7-0 ;M;1;1;0;2278.;325.;18.;0;0;0;0;0;0;0;0;;;;
wa;baldas fondo 2, 3, 5 y 6;;0;0;1;1162.;280.;18.;0;0;;;;;;;;;;
plb;puerta com·n batiente ;;0;0;1;2274.;297.;20.;0;1;2;192;0;0;0;0;0;0;;

El script es este:
Código
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. rem Saber en que linea vamos a cambiar:
  4. for /f "tokens=1 delims=:" %%# in ('type "file.txt" ^| findstr /i /n "puerta"') do (
  5. set "n_line=%%#"
  6. )
  7. rem La linea
  8. for /f "tokens=*" %%_ in ('type "file.txt" ^| findstr /i "puerta"') do (
  9. set "linea=%%_"
  10. )
  11. set /a "count=0"
  12. for /f "tokens=*" %%_ in (file.txt) do (
  13. set /a count+=1
  14. rem Mostrar normalmente:
  15. if !count! lss !n_line! (
  16. echo %%_
  17. )
  18. rem Sino, procesar:
  19. if !count! equ !n_line! (
  20. for /f "delims=; tokens=1-6*" %%a in ('echo !linea!') do (
  21. set "numero=%%f"
  22. set "numero=!numero:~0, -1!"
  23. set /a numero-=1
  24. echo %%a;%%b;;%%c;%%d;%%e;!numero!.;%%g
  25. )
  26. )
  27. )
  28.  

Obviamente tienes que volcar la salida a un archivo de texto nuevo, luego si quieres renombras.

Edit, esto también funciona:

Código
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /f "delims=: tokens=1-2*" %%a in ('type "file.txt" ^| findstr /i /n "puerta"') do (
  4. set "n_line=%%a"
  5. )
  6. for /f "tokens=*" %%_ in ('type "file.txt" ^| findstr /i "puerta"') do (
  7. set "linea=%%_"
  8. )
  9. for /f "delims=; tokens=1-6*" %%a in ('echo !linea!') do (
  10. set "numero=%%f"
  11. set "numero=!numero:~0, -1!"
  12. set /a numero-=1
  13. call:edit %%a "%%b" %%c %%d %%e !numero! "%%g"
  14. goto:eof
  15. )
  16. :edit
  17. ::
  18. (
  19. echo %n_line%
  20. echo %1;%~2;;%3;%4;%5;%6.;%~7 %~8
  21. echo w
  22. echo e
  23. ) | edlin /b file.txt > nul 2>&1
  24. goto:eof
  25.  
  26.  

Lo edita en el mismo lugar.


Título: Re: Modificar archivos de texto
Publicado por: bjeli1980 en 12 Mayo 2010, 09:41 am
Gracias a todos por responder.

- biribau, había pensado en hacerlo en perl ya que en batch me resultaba más dificil, tengo q probar la solución q me das, pero primero tendría que buscar primero si la línea contiene la palabra "puerta" o "frente"

- Leo, si que podemos utilizar aplicaciones externas. La palabra puerta o frente podría aparecer en más de una línea, por lo que habría que cambiarlo en varias líneas.

Voy a probar lo que me habeis puesto.

 ;) ;) ;) ;)

Ya lo he probado pero no me funciona para un fichero concreto. Me falla dentro de este for: for /f "tokens=*" %%_ in (file.txt) do (

Leo tengo que cambiarlo en 16000 ficheros, por lo que tengo q hacerlo de manera que no tenga que editarlos. Puede que la palabra puerta o frente no esté en ninguna línea del fichero, también puede ser que esté en diferentes lineas.



Título: Re: Modificar archivos de texto
Publicado por: bjeli1980 en 12 Mayo 2010, 12:29 pm
Al final lo he hecho en Perl, os pongo el código:

Muchas gracias a todos:

Código
  1. opendir(DIRHANDLE,".")||die "ERROR: no se puede leer directorio actual\n";
  2. foreach (readdir(DIRHANDLE)){
  3. next if ($_ eq "." || $_ eq "..");  
  4. next if (-d "$_" && ! -l "$_");  
  5. print $_ . "\n";
  6. open (ENTRADA,"<$_") || die "ERROR: No puedo abrir el fichero $_\n";
  7. #Los copio dentro la carpeta
  8. open (SALIDA,">modificados/$_") || die "ERROR: No puedo abrir el fichero $d/$_\n";
  9.  
  10.  
  11. while ($s=<ENTRADA>)
  12.  {
  13. my ($a, $_, $num, $b) = $s =~ m/(([^;]*;){6})([0-9]*)(.*)$/;
  14.  
  15. if (($s =~ /puerta/ ) || ($s =~ /frente/ ))
  16. {
  17. print "Encontrado";
  18. $num--;
  19. $s = $a . $_ . $num . $b;
  20. }
  21. print SALIDA $s;
  22.  }
  23.  close (ENTRADA);
  24.  close (SALIDA);
  25. }
  26. closedir DIRHANDLE;
  27.  


Título: Re: Modificar archivos de texto [batch] [Perl]
Publicado por: biribau en 12 Mayo 2010, 17:19 pm
      $s = $a . $_ . $num . $b;
El $_ lo había puesto ahí precisamente para que se notase que había que descartarlo, seguro que te funciona?
Porque hay unos paréntesis de una subexpresión que no interesa, pero hay que ponerlos por asociatividad  :-\


Título: Re: Modificar archivos de texto [batch] [Perl]
Publicado por: leogtz en 12 Mayo 2010, 23:20 pm
@bjeli1980

Como no habías especificado, lo hice para un solo archivo en concreto.
Hacerlo con 1600 archivos sería un engorro, además de que lentísimo.
Te felicito por la decisión de hacerlo en Perl.

Saludos.


Título: Re: Modificar archivos de texto [batch] [Perl]
Publicado por: bjeli1980 en 13 Mayo 2010, 17:15 pm
Tienes razón, no está bien, voy a echarle un vistazo.


Título: Re: Modificar archivos de texto [batch] [Perl]
Publicado por: bjeli1980 en 17 Mayo 2010, 09:07 am
Ahora creo que sí.

Lo he dejado así:

Código
  1. my ($a, $kk, $num, $b) = $s =~ m/(([^;]*;){6})([0-9]*)(.*)$/;
  2. $num--;
  3. $s = $a . $num . $b ."\n";