Shell : Découper un fichier en plusieurs fichiers

Shell : Découper un fichier en plusieurs fichiers - Shell/Batch - Programmation

Marsh Posté le 21-10-2009 à 15:20:55    

Bonjour,
voici mon problème:
 
j'ai un fichier person.txt dans lequel se trouve ces lignes:
 
<person>
<id>158</id>
<nom>Toto</nom>
<ville>Paris</ville>
</person>
 
<person>
<id>19521</id>
<nom>Mama</nom>
<ville>Bordeaux</ville>
</person>
 
<person>
<id>75142</id>
<nom>Kaka</nom>
<ville>Rennes</ville>
</person>
 
 
les <id>xxxxx</id> peut être n'importe quelle chiffre mais il y a "<id>xxxxx</id>" = N fois.
je voudrais découper ce fichier en N fichiers: fichier "person158" dans lequel se trouve:
<id>158</id>
<nom>Toto</nom>
<ville>Paris</ville>
 
Fichier "person19521" dans lequel se trouve
<id>19521</id>
<nom>Mama</nom>
<ville>Bordeaux</ville>
et ainsi de suite...
 
Je voudrais créer des fichiers .txt (person158.txt, person19521.txt ...) dans lesquelles
se trouvent les informations correspondants.
Dans "person158.txt" il y aura
 
<id>158</id>
<nom>Toto</nom>
<ville>Paris</ville>
 
dans "person19521.txt" il y aura
 
<id>19521</id>
<nom>Mama</nom>
<ville>Bordeaux</ville>
 
et ainsi de suite.
 
Il faut donc dans le fichier de départ rechercher les <id>xxxxx</id>, avec ces noms créer des fichiers "personxxxxx.txt"
et dans "personxxxxx.txt"  il faut copier les lignes se trouvant dans le fichier principal.  
 
je suis débutant en shell  
 
Help me please!!!!
merci


Message édité par sushi4556 le 21-10-2009 à 15:22:02
Reply

Marsh Posté le 21-10-2009 à 15:20:55   

Reply

Marsh Posté le 21-10-2009 à 16:01:00    

vu que ton fichier en entrée ressemble fortement à du xml, l'idéal serait d'utiliser un parser xml...

 

mais sinon, en quick&dirty (et en supposant que tout le fichier soit structuré comme ton exemple au niveau des retours chariots et toussa) tu peux t'en sortir avec un joli awk:

Code :
  1. awk 'match($0, "<id>.*</id>" ) {a = $0;
  2. gsub("<id>", "", a);
  3. gsub("</id>", "", a);
  4. system("echo \""$0"\" >> person"a".txt" );
  5. getline;
  6. system("echo \""$0"\" >> person"a".txt" );
  7. getline;
  8. system("echo \""$0"\" >> person"a".txt" )
  9. }' t

(ou t est ton fichier)


Message édité par pataluc le 21-10-2009 à 16:02:20
Reply

Marsh Posté le 21-10-2009 à 16:36:40    

Bonjour pataluc,
 
Premièrement, merci pour ta réponse, mais j'ai en fait N fichiers et pas seulement 3 fichiers. J'ai besoins donc de faire un boucle et c'est ici où je suis bloquée.
 
D'autre part, tu as parlé de "parser xml", peut-tu me donner quelques exemples s'il te plaît? Car cela sera la suite de mon boulot.  
 
Merci encore

Reply

Marsh Posté le 21-10-2009 à 16:52:06    

En fait, j'avais fait :
 
#!/bin/ksh
 
FICIN="person.txt"
typeset -i compteur=1
 
while read ligne ; do
     echo "$ligne" >> ${FICIN%%.*}_${compteur}.xml
     if [ $(echo "$ligne" | egrep -n '</person>' | wc -l ) -eq 1 ]; then
                           ((compteur = compteur+1))
     fi
 
done <$FICIN

 
Mais leur nom ne correspond pas ce que je souhaite.
J'ai obtenu
 
person1.txt dans lequel je trouve
<person>
<id>158</id>
<nom>Toto</nom>
<ville>Paris</ville>
</person>  
 
person2.txt dans lequel je trouve
<person>
<id>19521</id>
<nom>Mama</nom>
<ville>Bordeaux</ville>
</person>  
 
et ainsi person3.txt .........
 
 
Mais je souhaite que le nom de ces fichiers soit "personxxxxx.txt" où xxxxx est le numéro id.


Message édité par sushi4556 le 21-10-2009 à 16:52:32
Reply

Marsh Posté le 21-10-2009 à 16:54:23    

as tu au moins essayé mon code? parce qu'il fonctionne quel que soit le nombre de fichiers (il y a 3 lignes, correspondant aux trois lignes id, nom et ville)...

 

et sinon pour les parser xml, google est ton ami... ^^ (il te faudra cependant lacher le ksh pour un langage type perl, python, java, etc)


Message édité par pataluc le 21-10-2009 à 16:56:09
Reply

Marsh Posté le 21-10-2009 à 17:24:34    

On a droit au perl ?

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. my $id;
  5. my $output_file;
  6. my $output;
  7. while(<> ) {
  8.         if (/<id>(\d+)<\/id>/) {
  9.                 $id=$1;
  10.                 $output=$_;
  11.         } elsif (/<\/person>/) {
  12.                 open $output_file, '>', "person$id.txt" or die("person$id.txt: $!" );
  13.                 print $output_file $output;
  14.                 close $output_file;
  15.         } elsif (! /^\s+$/) {
  16.                 $output.=$_;
  17.         }
  18. }
 

Usage :

perl split.pl person.txt

 

Fonctionne quelque soit le contenu du fichier source (s'il y a 10 lignes pour une personne, ça marche) : ressort tout ce qui est compris entre un <id>xxxx</id> et </person> (</person> non compris) dans un fichier personxxxx.txt

 

Peut être adapté pour prendre en compte des espaces dans la ligne <id>xxxx</id> si besoin.

 

edit: ça n'est pas non plus un parser, mais bon, il permet de gérer plusieurs lignes =) et puis j'aime bien perl...


Message édité par lennelei le 21-10-2009 à 17:30:01
Reply

Marsh Posté le 21-10-2009 à 17:53:54    

Sinon, ton idée était bonne, il suffit de récupérer l'id pour nommer le fichier plutôt que d'utiliser un compteur :

 
Code :
  1. #!/bin/ksh
  2. FICIN="person.txt"
  3. typeset -i compteur=0
  4. while read ligne ; do
  5.      if [ $(echo "$ligne" | egrep '<id>' |cut -d'>' -f2 |cut -d'<' -f1 | wc -l ) -eq 1 ]; then
  6.         (( compteur = $(echo "$ligne" | egrep '<id>' |cut -d'>' -f2 |cut -d'<' -f1 ) ))
  7.      fi
  8.      if [ $(echo "$ligne" | egrep -n '</person>' | wc -l ) -eq 1 ]; then
  9.         ((compteur = 0))
  10.      fi
  11.      echo "$ligne" >> ${FICIN%%.*}_${compteur}.xml
  12. done <$FICIN
 

A noter qu'un fichier person_0.txt est créé et contient toutes les lignes que tu ne prends pas (<person> et </person> et les lignes entre par exemple), c'est pour ça que le echo est à la fin.


Message édité par lennelei le 21-10-2009 à 17:54:28
Reply

Marsh Posté le 22-10-2009 à 10:10:36    

pourquoi faire en 16 ligne et je ne sais combien de commandes ce qui se fait un un seul awk de moitié moins de lignes? (je fais abstraction des sous commandes system passées dans le awk)
 
 :whistle:


Message édité par pataluc le 22-10-2009 à 10:10:49
Reply

Marsh Posté le 22-10-2009 à 12:45:17    

Parce qu'au départ, elle partait d'un ksh et qu'après réflexion, je me suis dit qu'on pouvait le faire en ksh sans utiliser awk ou perl.
Donc plutôt que de lui filer uniquement une solution en perl/awk, je lui montre comment faire à partir de ce qu'elle a écrit, c'est plus formateur que de balancer 20 lignes de codes en perl ou awk si elle ne connait pas perl / awk ? (oui, je sais, elle a intérêt à l'apprendre un jour =)

 


Message édité par lennelei le 22-10-2009 à 12:45:31
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed