Selection ligne suivante CSH foreach
Résolu/Fermé
A voir également:
- Selection ligne suivante CSH foreach
- Aller à la ligne excel - Guide
- Vente en ligne particulier - Guide
- Partage de photos en ligne - Guide
- Apparaitre hors ligne instagram - Guide
- Gps hors ligne - Guide
11 réponses
zipe31
Messages postés
36402
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
6 415
2 févr. 2011 à 14:29
2 févr. 2011 à 14:29
Bon c'est pour un shell bash, il te faudra adapter la syntaxe pour le csh...
;-))
$ cat plop simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete $ cat foo.sh #! /bin/bash #set -xv while read line do sed -i "/${line% *}/{s/ok x/ok ${line#* }/}" plop done < <(awk '{ print $1 }' plop | uniq -c | awk '{ print $2,$1 }') $ ./foo.sh $ cat plop simon ok 4 febgeg simon ok 4 rhedg simon ok 4 erze simon ok 4 srg e fabien ok 2 nrteth fabien ok 2 tehhet seb ok 1 et ee yoann ok 6 eth yoann ok 6 et he yoann ok 6 ehe yoann ok 6 egr yoann ok 6 ereh yoann ok 6 ete $
;-))
zipe31
Messages postés
36402
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
6 415
2 févr. 2011 à 16:51
2 févr. 2011 à 16:51
$ cat plop simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete $ cat csh_foo.csh #! /bin/csh foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' ) set line = "$line:gas/|/ /" set argv = ( $line ) sed "/$1/{s/ok x/ok $2/}" plop > blop mv blop plop end $ ./csh_foo.csh $ cat plop simon ok 4 febgeg simon ok 4 rhedg simon ok 4 erze simon ok 4 srg e fabien ok 2 nrteth fabien ok 2 tehhet seb ok 1 et ee yoann ok 6 eth yoann ok 6 et he yoann ok 6 ehe yoann ok 6 egr yoann ok 6 ereh yoann ok 6 ete $
;-))
RE Merci ^^
Il me renvoi ça : "Missing }"
rien d'autre c'est bizarre ... j'ai essayé de modifier ( remplacé les acolades etc ... mais rien ne marche ça fai tout le temps des erreurs.
Mais je comprend pas tu as fais ça sur une konsole en CSH alors pourquoi ca marche pas chez moi ? rrrr pourquoi j'ai jamais de chance avec l'informatique ? :/
Il me renvoi ça : "Missing }"
rien d'autre c'est bizarre ... j'ai essayé de modifier ( remplacé les acolades etc ... mais rien ne marche ça fai tout le temps des erreurs.
Mais je comprend pas tu as fais ça sur une konsole en CSH alors pourquoi ca marche pas chez moi ? rrrr pourquoi j'ai jamais de chance avec l'informatique ? :/
zipe31
Messages postés
36402
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
6 415
3 févr. 2011 à 09:30
3 févr. 2011 à 09:30
Re-
Il me renvoi ça : "Missing }"
rien d'autre c'est bizarre ... j'ai essayé de modifier ( remplacé les acolades etc ... mais rien ne marche ça fai tout le temps des erreurs.
Essaye de procéder petit à petit (c'est ce que j'ai fait hier, vu que le csh n'est pas ma tasse de thé et que j'avais des erreurs comme toi et notamment le fameux "Missing }" ;-((
Donc pour commencer :
Et vois si tu as toujours des erreurs.
Attention toutefois, le code du forum interprète très mal les quotes inverses " ' " (Alt Gr + 7 le 7 du pavé alphanumérique celui au dessus des touches Y et U), donc dans l'expression :
foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' )
c'est bien une quote inversée avant le 1er awk et avant la dernière parenthèse fermante, hein ?
Mais je comprend pas tu as fais ça sur une konsole en CSH alors pourquoi ca marche pas chez moi ? rrrr pourquoi j'ai jamais de chance avec l'informatique ? :/
J'ai du l'installer hier sur une Mandriva 2010, ce n'est plus fourni par défaut, et à ce titre c'est du tcsh qui s'est installé, peut être est-ce du à cela ;-\
Il me renvoi ça : "Missing }"
rien d'autre c'est bizarre ... j'ai essayé de modifier ( remplacé les acolades etc ... mais rien ne marche ça fai tout le temps des erreurs.
Essaye de procéder petit à petit (c'est ce que j'ai fait hier, vu que le csh n'est pas ma tasse de thé et que j'avais des erreurs comme toi et notamment le fameux "Missing }" ;-((
Donc pour commencer :
#! /bin/csh foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' ) echo $line end
Et vois si tu as toujours des erreurs.
Attention toutefois, le code du forum interprète très mal les quotes inverses " ' " (Alt Gr + 7 le 7 du pavé alphanumérique celui au dessus des touches Y et U), donc dans l'expression :
foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' )
c'est bien une quote inversée avant le 1er awk et avant la dernière parenthèse fermante, hein ?
Mais je comprend pas tu as fais ça sur une konsole en CSH alors pourquoi ca marche pas chez moi ? rrrr pourquoi j'ai jamais de chance avec l'informatique ? :/
J'ai du l'installer hier sur une Mandriva 2010, ce n'est plus fourni par défaut, et à ce titre c'est du tcsh qui s'est installé, peut être est-ce du à cela ;-\
$ ls -l /bin/csh lrwxrwxrwx 1 root root 4 2011-02-02 15:19 /bin/csh -> tcsh* $ urpmq -fi tcsh Name : tcsh Version : 6.15 Release : 6.4mdv2010.0 Group : Shells Size : 616513 Architecture: i586 Source RPM : tcsh-6.15-6.4mdv2010.0.src.rpm URL : http://www.tcsh.org/ Summary : An enhanced version of csh, the C shell Description : Tcsh is an enhanced but completely compatible version of csh, the C shell. Tcsh is a command language interpreter which can be used both as an interactive login shell and as a shell script command processor. Tcsh includes a command line editor, programmable word completion, spelling correction, a history mechanism, job control and a C language like syntax.
humm alors aucun souci pour :
#! /bin/csh
foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' )
echo $line
end
ca marche très bien !
par contre quant je remet tout ( avec les bonnes quotes ^^ ) il met : Variable syntax
il y a qu'une variable je pense : $line et je voi pas pourquoi !
Comme tu as remarqué je suis très nul en CSH :/ désolé
#! /bin/csh
foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' )
echo $line
end
ca marche très bien !
par contre quant je remet tout ( avec les bonnes quotes ^^ ) il met : Variable syntax
il y a qu'une variable je pense : $line et je voi pas pourquoi !
Comme tu as remarqué je suis très nul en CSH :/ désolé
zipe31
Messages postés
36402
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
6 415
3 févr. 2011 à 10:01
3 févr. 2011 à 10:01
Essaie de supprimer les accolades dans l'expression avec sed :
sed "/$1/{s/ok x/ok $2/}" plop > blopà transformer en :
sed "/$1/s/ok x/ok $2/" plop > blop
zipe31
Messages postés
36402
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
6 415
2 févr. 2011 à 13:18
2 févr. 2011 à 13:18
Salut,
Au cas ou... des outils tous prêts existent sous GNU/Linux...
;-))
Au cas ou... des outils tous prêts existent sous GNU/Linux...
$ cat plop simon ok x simon ok x simon ok x simon ok x fabien ok x fabien ok x seb ok x yoann ok x yoann ok x yoann ok x yoann ok x yoann ok x yoann ok x $ uniq -c plop 4 simon ok x 2 fabien ok x 1 seb ok x 6 yoann ok x $
;-))
merci bien pour ta réponse . Cependant ça compare les lignes et moi je ne veu comparer que la premiere colonne .
Car par exemple avec
simon ok x febgeg
simon ok x rhedg
simon ok x erze
simon ok x srg e
fabien ok x nrteth
fabien ok x tehhet
seb ok x et ee
yoann ok x eth
yoann ok x et he
yoann ok x ehe
yoann ok x egr
yoann ok x ereh
yoann ok x ete
ca ne marche pas :/
et c'est un fichier énorme donc le mieu serait de modifié directement :
Sachant que les lignes avec les premieres colone égale se suivent forcement (ouf)
Compter le nombre docurence du premier terme ( ex : simon ) puis metre en 3 eme colone ce nombre.
en gro:
L1 simon -> count = 1
L2 simon -> count = 2
L3 simon -> count = 3
L4 simon -> count = 4
L5 fabien -> count = 4 et on met 4 en 3eme colone de simon puis on remet count a 0
c'est en gro se que je veu faire...
mais sinon deja j'aimerai savoir : Comment récuperer un element a N+1 ? ( cf premiere question)
Grand merci
Car par exemple avec
simon ok x febgeg
simon ok x rhedg
simon ok x erze
simon ok x srg e
fabien ok x nrteth
fabien ok x tehhet
seb ok x et ee
yoann ok x eth
yoann ok x et he
yoann ok x ehe
yoann ok x egr
yoann ok x ereh
yoann ok x ete
ca ne marche pas :/
et c'est un fichier énorme donc le mieu serait de modifié directement :
Sachant que les lignes avec les premieres colone égale se suivent forcement (ouf)
Compter le nombre docurence du premier terme ( ex : simon ) puis metre en 3 eme colone ce nombre.
en gro:
L1 simon -> count = 1
L2 simon -> count = 2
L3 simon -> count = 3
L4 simon -> count = 4
L5 fabien -> count = 4 et on met 4 en 3eme colone de simon puis on remet count a 0
c'est en gro se que je veu faire...
mais sinon deja j'aimerai savoir : Comment récuperer un element a N+1 ? ( cf premiere question)
Grand merci
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
3 févr. 2011 à 20:05
3 févr. 2011 à 20:05
Salut,
Cependant ça compare les lignes et moi je ne veu comparer que la premiere colonne .
Ben, pas pour moi.
D'après ce que je vois tu veux comparer les lignes mais juste sur un seul critère: le 1er mot de la ligne.
Cependant ça compare les lignes et moi je ne veu comparer que la premiere colonne .
Ben, pas pour moi.
D'après ce que je vois tu veux comparer les lignes mais juste sur un seul critère: le 1er mot de la ligne.
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
3 févr. 2011 à 20:09
3 févr. 2011 à 20:09
Par exemple c'est ça que je vois
:~$ cat visiteurr simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete :~$ perl -ne 's/^(.*?)\s.*/$1. "-> count " . ($h{$1}++ + 1)/e;print' visiteurr simon-> count 1 simon-> count 2 simon-> count 3 simon-> count 4 fabien-> count 1 fabien-> count 2 seb-> count 1 yoann-> count 1 yoann-> count 2 yoann-> count 3 yoann-> count 4 yoann-> count 5 yoann-> count 6
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
3 févr. 2011 à 20:13
3 févr. 2011 à 20:13
:~$ cat visiteurr simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete :~$ perl -ne 's/^(.*?)\s(.*?)\sx(.*)/"$1 $2 " .($h{$1}++ + 1) . "$3"/e;print' visiteurr simon ok 1 febgeg simon ok 2 rhedg simon ok 3 erze simon ok 4 srg e fabien ok 1 nrteth fabien ok 2 tehhet seb ok 1 et ee yoann ok 1 eth yoann ok 2 et he yoann ok 3 ehe yoann ok 4 egr yoann ok 5 ereh yoann ok 6 ete
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
3 févr. 2011 à 21:20
3 févr. 2011 à 21:20
Re,
Bon, il doit avoir plus simple mais je pense à quelque chose de genre :
- on obtiens le nombre d'occurrences et on les stocke dans un fichier temp
- on utilise le fichier temp et on insère le nombre d'occurrences dans le fichier
Bon, il doit avoir plus simple mais je pense à quelque chose de genre :
- on obtiens le nombre d'occurrences et on les stocke dans un fichier temp
:~$ perl -ane '$h{$F[0]}++;END{print "$_:$h{$_}\n" for keys %h}' visiteurr > visiteurr.occ lami20j@debian-acer:~$ cat visiteurr.occ seb:1 yoann:6 simon:4 fabien:2
- on utilise le fichier temp et on insère le nombre d'occurrences dans le fichier
:~$ cat visiteurr simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete :~$ perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr simon ok 4 febgeg simon ok 4 rhedg simon ok 4 erze simon ok 4 srg e fabien ok 2 nrteth fabien ok 2 tehhet seb ok 1 et ee yoann ok 6 eth yoann ok 6 et he yoann ok 6 ehe yoann ok 6 egr yoann ok 6 ereh yoann ok 6 ete
zipe31
Messages postés
36402
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
6 415
4 févr. 2011 à 11:46
4 févr. 2011 à 11:46
Re-
Normalement Perl est installé sur tous les système GNU/Linux par défaut et ne dépend en rien du shell de connexion.
Il est aussi sensé être plus adapté à ce genre de traitement ;-))
PS. Je réponds à sa place sachant qu'il ne se connectera pas avant ce soir, sauf s'il veut me faire mentir ;-))
Normalement Perl est installé sur tous les système GNU/Linux par défaut et ne dépend en rien du shell de connexion.
Il est aussi sensé être plus adapté à ce genre de traitement ;-))
PS. Je réponds à sa place sachant qu'il ne se connectera pas avant ce soir, sauf s'il veut me faire mentir ;-))
zipe31
Messages postés
36402
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
6 415
4 févr. 2011 à 11:50
4 févr. 2011 à 11:50
Bon courage on compatit ;-\
oula lol j'ai rien modifier a par les noms de fichier et j'ai l'impression que ca marche ... je comrpend pas la lol
Où on selectionne la colonne a modifié ? pouvez vous m'expliquer cette commande ?
:~$ perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr
Où on selectionne la colonne a modifié ? pouvez vous m'expliquer cette commande ?
:~$ perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
6 févr. 2011 à 10:20
6 févr. 2011 à 10:20
Salut,
1ère commande
perl -ane '$h{$F[0]}++;END{print "$_:$h{$_}\n" for keys %h}' visiteurr > visiteurr.occ
Le rôle de cette commande c'est de compter le nombre d'occurrence du mot se trouvant au début des lignes du fichier.
Pour cela j'utilise la structure de donné appelée hash ou tableau associatif.
Cette structure de donnée permet d'accéder aux éléments de tableau par une clé (qui est une chaîne de caractère).
A chaque clé correspond une valeur (qui peut être une chaîne, un nombre, un tableau, un hash, une référence, bref un peu tout ;-)
Ce qui donne la présentation suivante
A savoir que la clé est unique.
Dans ton exemple la commande va parcourir chaque ligne de fichier.
Vu qu'on cherche le nombre d'occurrence du 1er mot de chaque ligne alors il suffit de considérer le 1er mot comme clé et vu qu'elle devrait être unique alors il me suffira par la suite de compter la valeur.
Voici ce qui se passe sur le capot.
Traitement de la 1ère ligne
la clé est simon et la valeur sera 1
Traitement de la 2ème ligne
la clé est simon et la valeur sera 2 (la valeur est incrementé à chaque passage)
Tout ça pour tout les simon quelque soit le numéro de la ligne dans le fichier (donc les ligens ayant simon au début n'ont pas besoin d'être groupée)
Quand on arrive à fabien alors c'est une nouvelle clé et à l'instar de la clé simon la valeur sera incrémenté et ainsi de suite jusqu'à la dernière ligne de fichier.
A la fin le hash a un peu cette forme (à savoir qu'on peut trier le hash mais pas besoin dans ce cas) qui est interne donc aléatoire et pas dans l'ordre de création de hash
A ce moment le hash est dans la mémoire vive et il faudrait le sauvegarder quelque part, j'ai choisi un fichier.
Le bloc END{} permet qu'une fois arrivé à la fin de fichier, d'afficher le hash.
Pour enregistrer dans le fichier j'ai utiliser une simple redirection de STDOUT (sortie standard, l'écran) vers un fichier.
Voilà le fonctionnement pour la 1ère commande.
Les option utiliser permet de spliter les mots de chaque ligne dans un tableau @F et ensuite j'utilise $F[0] - le 1er élément (simon, seb, fabien, yoann)
La 2ème commande
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr
Cette commande lit les deux fichiers :
- celui créé par le 1ère commande qui contient le nombre d'occurences
- le fichier original.
La commande contient deux lignes de code séparées par point-virgule
$h{$1}=$2 if /(.*):(.*)/
et
s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print
La commande $h{$1}=$2 if /(.*):(.*)/ au moment de la lecture du 1er fichier va recréer le hash.
Cette fois si le séparateur n'est plus l'espace mais les deux points
(.*):(.*) c'est une expression régulière qu'on pourrait la traduire comme ça
. veut dire n'importe quel caractère
*</gas> c'est un quantificateur qui permet de trouver 0,1 ou n'importe combien de caractères
<gras>() les parenthèses c'est pour capturer le motif trouvé
: c'est le caractère littéral
Les captures sont numéroté de 1 à .... et les variables correspondante sont $1, $2 .....
Ce qui est intéressant c'est que le hash sera rempli si est seulement la ligne contient un : (ça pourrait poser des problèmes de mémoires pas de résultat si le fichier original contiendra :)
On pourrait améliorer en utilisant les ancrages de début et fin chaîne. (^ - début ; $ - fin)
Tu pourrais te demander pourquoi on ne l'as pas fait d'un coup au lieu de créer un fichier temporaire.
Si le fichier est de grande taille (disons des millions des lignes) alors je te laisse imaginé de combien de mémoire vive + swap on devrait avoir pour stoker tout ça.
Bon le cas le plus défavorable sera si le fichier original contiendrait une clé par ligne, mais en ce cas il n'y aura plus besoin de compter le nombre d'occurrences et en ce cas l'ajout du 1 dans le colonne serait suffisant
Donc $h{$1}=$2 if /(.*):(.*)/ dit en bref : remplie moi le hash avec cle => valeur si est seulement la ligne lu dans le fichier contient :
A la fin de la lecture du 1er fichier, le hash est rempli et c'est la lecture du fichier original qui commence.
s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print
Sachant que le séparateur est l'espace alors il suffit de séparer les mots et ensuite remplacer le x avec la valeur correspondant qui se trouve dans le hash
s/MOTIF/REMPLACEMENT/ c'est la fonction substitute qui permet de remplacer la partie gauche avec ce qui se trouve à droite
La partie MOTIF
s/^(.*?)\s(.*?)\sx(.*)/
s/
^ -ancrage début chaine
( - début 1ère capture - $1
.*? - n'importe quel caractère 0,1 ou n'importe combien des fois mais éviter la gourmandise
) - fin 1ère capture
\s - cherche un espace
( - début 2ème capture - $2
.*? - n'importe quel caractère 0,1 ou n'importe combien des fois mais éviter la gourmandise
) - fin 2ème capture
\sx - c'est ici le champ concerné pour le changement
( - la 3ème capture - $3
.* - n'importe quel caractère 0,1 ou n'importe combien des fois, gourmande cette fois
) - fin de la 3ème capture
Attention, si la colonne a modifié ne contient pas x alors il faudrai changer la regex
La partie REMPLACEMENT
/$1 $2 $h{$1} $3/ and print
/
$1 - la 1ère capture
$2 - espace la 2ème capture
$h{$1} - espace et voir (nombre occurrence)
$3 - espace et la 3ème capture
/ and print - fin de remplacement et affiche
nombre occurence $h{$1}
La 1ère capture c'est le 1ère mot de la ligne.
$h{$1} par exemple quand le mot est simon on a :
$h{"simon"} et dans le hash on a vu que la valeur de simon est le nombre d'occurrences trouvées par le 1ère commande, donc 4
Cette substitution est appliquée pour chaque ligne.
Voilà, j'espère que c'est un peu plus clair.
c'est lui le spécialiste en Perl ;-))
Pas menteur en ce qui concerne la connexion, mais pour le reste oui ;-))
1ère commande
perl -ane '$h{$F[0]}++;END{print "$_:$h{$_}\n" for keys %h}' visiteurr > visiteurr.occ
Le rôle de cette commande c'est de compter le nombre d'occurrence du mot se trouvant au début des lignes du fichier.
Pour cela j'utilise la structure de donné appelée hash ou tableau associatif.
Cette structure de donnée permet d'accéder aux éléments de tableau par une clé (qui est une chaîne de caractère).
A chaque clé correspond une valeur (qui peut être une chaîne, un nombre, un tableau, un hash, une référence, bref un peu tout ;-)
Ce qui donne la présentation suivante
%hash = ( "cle1" => "valeur", "cle2" => "autre valeur", .... "cleN" => "et encore une valeur", );
A savoir que la clé est unique.
Dans ton exemple la commande va parcourir chaque ligne de fichier.
Vu qu'on cherche le nombre d'occurrence du 1er mot de chaque ligne alors il suffit de considérer le 1er mot comme clé et vu qu'elle devrait être unique alors il me suffira par la suite de compter la valeur.
Voici ce qui se passe sur le capot.
Traitement de la 1ère ligne
la clé est simon et la valeur sera 1
Traitement de la 2ème ligne
la clé est simon et la valeur sera 2 (la valeur est incrementé à chaque passage)
Tout ça pour tout les simon quelque soit le numéro de la ligne dans le fichier (donc les ligens ayant simon au début n'ont pas besoin d'être groupée)
Quand on arrive à fabien alors c'est une nouvelle clé et à l'instar de la clé simon la valeur sera incrémenté et ainsi de suite jusqu'à la dernière ligne de fichier.
A la fin le hash a un peu cette forme (à savoir qu'on peut trier le hash mais pas besoin dans ce cas) qui est interne donc aléatoire et pas dans l'ordre de création de hash
%h = ( "seb" => 1, "yoann" => 6, "simon" => 4, "fabien" => 2, );
A ce moment le hash est dans la mémoire vive et il faudrait le sauvegarder quelque part, j'ai choisi un fichier.
Le bloc END{} permet qu'une fois arrivé à la fin de fichier, d'afficher le hash.
Pour enregistrer dans le fichier j'ai utiliser une simple redirection de STDOUT (sortie standard, l'écran) vers un fichier.
Voilà le fonctionnement pour la 1ère commande.
Les option utiliser permet de spliter les mots de chaque ligne dans un tableau @F et ensuite j'utilise $F[0] - le 1er élément (simon, seb, fabien, yoann)
La 2ème commande
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr
Cette commande lit les deux fichiers :
- celui créé par le 1ère commande qui contient le nombre d'occurences
- le fichier original.
La commande contient deux lignes de code séparées par point-virgule
$h{$1}=$2 if /(.*):(.*)/
et
s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print
La commande $h{$1}=$2 if /(.*):(.*)/ au moment de la lecture du 1er fichier va recréer le hash.
Cette fois si le séparateur n'est plus l'espace mais les deux points
(.*):(.*) c'est une expression régulière qu'on pourrait la traduire comme ça
. veut dire n'importe quel caractère
*</gas> c'est un quantificateur qui permet de trouver 0,1 ou n'importe combien de caractères
<gras>() les parenthèses c'est pour capturer le motif trouvé
: c'est le caractère littéral
Les captures sont numéroté de 1 à .... et les variables correspondante sont $1, $2 .....
Ce qui est intéressant c'est que le hash sera rempli si est seulement la ligne contient un : (ça pourrait poser des problèmes de mémoires pas de résultat si le fichier original contiendra :)
On pourrait améliorer en utilisant les ancrages de début et fin chaîne. (^ - début ; $ - fin)
Tu pourrais te demander pourquoi on ne l'as pas fait d'un coup au lieu de créer un fichier temporaire.
Si le fichier est de grande taille (disons des millions des lignes) alors je te laisse imaginé de combien de mémoire vive + swap on devrait avoir pour stoker tout ça.
Bon le cas le plus défavorable sera si le fichier original contiendrait une clé par ligne, mais en ce cas il n'y aura plus besoin de compter le nombre d'occurrences et en ce cas l'ajout du 1 dans le colonne serait suffisant
Donc $h{$1}=$2 if /(.*):(.*)/ dit en bref : remplie moi le hash avec cle => valeur si est seulement la ligne lu dans le fichier contient :
A la fin de la lecture du 1er fichier, le hash est rempli et c'est la lecture du fichier original qui commence.
s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print
Sachant que le séparateur est l'espace alors il suffit de séparer les mots et ensuite remplacer le x avec la valeur correspondant qui se trouve dans le hash
s/MOTIF/REMPLACEMENT/ c'est la fonction substitute qui permet de remplacer la partie gauche avec ce qui se trouve à droite
La partie MOTIF
s/^(.*?)\s(.*?)\sx(.*)/
s/
^ -ancrage début chaine
( - début 1ère capture - $1
.*? - n'importe quel caractère 0,1 ou n'importe combien des fois mais éviter la gourmandise
) - fin 1ère capture
\s - cherche un espace
( - début 2ème capture - $2
.*? - n'importe quel caractère 0,1 ou n'importe combien des fois mais éviter la gourmandise
) - fin 2ème capture
\sx - c'est ici le champ concerné pour le changement
( - la 3ème capture - $3
.* - n'importe quel caractère 0,1 ou n'importe combien des fois, gourmande cette fois
) - fin de la 3ème capture
Attention, si la colonne a modifié ne contient pas x alors il faudrai changer la regex
La partie REMPLACEMENT
/$1 $2 $h{$1} $3/ and print
/
$1 - la 1ère capture
$2 - espace la 2ème capture
$h{$1} - espace et voir (nombre occurrence)
$3 - espace et la 3ème capture
/ and print - fin de remplacement et affiche
nombre occurence $h{$1}
La 1ère capture c'est le 1ère mot de la ligne.
$h{$1} par exemple quand le mot est simon on a :
$h{"simon"} et dans le hash on a vu que la valeur de simon est le nombre d'occurrences trouvées par le 1ère commande, donc 4
Cette substitution est appliquée pour chaque ligne.
Voilà, j'espère que c'est un peu plus clair.
c'est lui le spécialiste en Perl ;-))
Pas menteur en ce qui concerne la connexion, mais pour le reste oui ;-))
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
Modifié par lami20j le 9/02/2011 à 18:01
Modifié par lami20j le 9/02/2011 à 18:01
Salut,
A vrai dire mon test est fait sur un exemple qui semble n'est pas être conforme à ton fichier.
Pour ça j'aurais peut être besoin de ton fichier.
Tu peux me l'envoyer par mail.
petite précision aussi ... diference entre ".*?" et juste ".*" ?
Voici un exemple pour voir la différence.
Tu remarques quand j'utilise .* alors $1 vaut xigenc - .* a avalé tout jusqu'au dernière e, donc la plus longue chaine
En revanche quand j'utilise .*? alors $1 vaut xig - .*? a avalé jusqu'au 1er e, donc la chaine minimale
A vrai dire mon test est fait sur un exemple qui semble n'est pas être conforme à ton fichier.
Pour ça j'aurais peut être besoin de ton fichier.
Tu peux me l'envoyer par mail.
petite précision aussi ... diference entre ".*?" et juste ".*" ?
Voici un exemple pour voir la différence.
Tu remarques quand j'utilise .* alors $1 vaut xigenc - .* a avalé tout jusqu'au dernière e, donc la plus longue chaine
En revanche quand j'utilise .*? alors $1 vaut xig - .*? a avalé jusqu'au 1er e, donc la chaine minimale
:~$ echo exigence exigence :~$ echo exigence | perl -ne '/e(.*)e/ ; print "$1\n"' xigenc r:~$ echo exigence | perl -ne '/e(.*?)e/ ; print "$1\n"' xig
zipe31
Messages postés
36402
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
6 415
7 févr. 2011 à 19:12
7 févr. 2011 à 19:12
Salut,
Pour ça j'aurais peut être besoin de ton fichier.
Tu peux me l'envoyer par mail.
Déjà demandé, mais ce n'est pas possible, par contre les lignes originelles ressemblent à ça ;-\
Pour ça j'aurais peut être besoin de ton fichier.
Tu peux me l'envoyer par mail.
Déjà demandé, mais ce n'est pas possible, par contre les lignes originelles ressemblent à ça ;-\
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
7 févr. 2011 à 19:20
7 févr. 2011 à 19:20
Salut,
Déjà demandé, mais ce n'est pas possible, par contre les lignes originelles ressemblent
Ben, c'est justement ça qui me dérange que ça rassemble, mais personne ne dit ce qui se trouve derrière les caractères non imprimables (espace, tabulation, ou je ne sais pas quoi encore ;-)
Je vais essayer de généraliser.
Déjà demandé, mais ce n'est pas possible, par contre les lignes originelles ressemblent
Ben, c'est justement ça qui me dérange que ça rassemble, mais personne ne dit ce qui se trouve derrière les caractères non imprimables (espace, tabulation, ou je ne sais pas quoi encore ;-)
Je vais essayer de généraliser.
zipe31
Messages postés
36402
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
6 415
7 févr. 2011 à 19:25
7 févr. 2011 à 19:25
Faut faire avec.... mais c'est là qu'on voit les véritables bêtes au final ;-))
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
7 févr. 2011 à 20:06
7 févr. 2011 à 20:06
Re,
je comprend pas comment "simuler" des colonnes ...
Vous savez ?
Alors on va essayer de savoir la structure de ton fichier.
Avec cette commande tous les caractères différent des espace, tab sont remplacés par A et les autres par leur code ascii.
perl -ne 'while(/(.)/g){my $x=$1;($x=~/\s/)?(print " ", ord($x), " "):print "A"};print "\n"' visiteurr > visit.struct
Ensuite tu mets le fichier visit.struct sur cjoint.com
Pour preuve voici ce qui affiche chez moi
je comprend pas comment "simuler" des colonnes ...
Vous savez ?
Alors on va essayer de savoir la structure de ton fichier.
Avec cette commande tous les caractères différent des espace, tab sont remplacés par A et les autres par leur code ascii.
perl -ne 'while(/(.)/g){my $x=$1;($x=~/\s/)?(print " ", ord($x), " "):print "A"};print "\n"' visiteurr > visit.struct
Ensuite tu mets le fichier visit.struct sur cjoint.com
Pour preuve voici ce qui affiche chez moi
~$ cat visiteurr simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete ~$ perl -ne 'while(/(.)/g){my $x=$1;($x=~/\s/)?(print " ", ord($x), " "):print "A"};print "\n"' visiteurr > visit.struct lami20j@debian-acer:~$ cat visit.struct AAAAA 32 AA 32 A 32 AAAAAA AAAAA 32 AA 32 A 32 AAAAA AAAAA 32 AA 32 A 32 AAAA AAAAA 32 AA 32 A 32 AAA 32 A AAAAAA 32 AA 32 A 32 AAAAAA AAAAAA 32 AA 32 A 32 AAAAAA AAA 32 AA 32 A 32 AA 32 AA AAAAA 32 AA 32 A 32 AAA AAAAA 32 AA 32 A 32 AA 32 AA AAAAA 32 AA 32 A 32 AAA AAAAA 32 AA 32 A 32 AAA AAAAA 32 AA 32 A 32 AAAA AAAAA 32 AA 32 A 32 AAA 32
RE ^^ alors aprés avoir longement modifié le code pour tenté de l'adapter ^^ voila ce que j'obtient:
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\tmodification\t(.*)/$1\t$h{$1}\t$2/ and print' texte.txt.occ texte.tmp.3_2 > texte.txt.tmp.3_3
avec des lignes de ce type :
simon modification 9999.00 test 999.00 tes2 test3 pierre 99.00 test4 yoann 99.00 99.00 grande_phrase 9999999.00 99.00 99.00 9.00 99.00 didier
et ca marche super bien
Malheureusement je n'ai en aucun cas le droit de sortir un document même modifié de mon entreprise ... De plus le fichier possède 16000 lignes trés trés longues ^^ tu me diras c'est pas grand chose lol j'en ai un qui posséde plus de 4 millions de lignes =) ( plus de 200Mo ).
Sur mon exemple si dessu chaque mot est dans une colonne différente et le résultat doit etre :
simon 8 9999.00 test 999.00 tes2 test3 pierre 99.00 test4 yoann 99.00 99.00 grande_phrase 9999999.00 99.00 99.00 9.00 99.00 didier
si Simon aparait 8 fois en première position.
Que pensez vous de mes modifs ? c'est normale que ca marche ou c'est un coup de chance et ca va pas marcher tout le temps ?
Merci les gars c'est vraiment sympa
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\tmodification\t(.*)/$1\t$h{$1}\t$2/ and print' texte.txt.occ texte.tmp.3_2 > texte.txt.tmp.3_3
avec des lignes de ce type :
simon modification 9999.00 test 999.00 tes2 test3 pierre 99.00 test4 yoann 99.00 99.00 grande_phrase 9999999.00 99.00 99.00 9.00 99.00 didier
et ca marche super bien
Malheureusement je n'ai en aucun cas le droit de sortir un document même modifié de mon entreprise ... De plus le fichier possède 16000 lignes trés trés longues ^^ tu me diras c'est pas grand chose lol j'en ai un qui posséde plus de 4 millions de lignes =) ( plus de 200Mo ).
Sur mon exemple si dessu chaque mot est dans une colonne différente et le résultat doit etre :
simon 8 9999.00 test 999.00 tes2 test3 pierre 99.00 test4 yoann 99.00 99.00 grande_phrase 9999999.00 99.00 99.00 9.00 99.00 didier
si Simon aparait 8 fois en première position.
Que pensez vous de mes modifs ? c'est normale que ca marche ou c'est un coup de chance et ca va pas marcher tout le temps ?
Merci les gars c'est vraiment sympa
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
8 févr. 2011 à 12:33
8 févr. 2011 à 12:33
Salut,
c'est normale que ca marche ou c'est un coup de chance et ca va pas marcher tout le temps ?
Ce que j'ai besoin ce n'est pas le contenu mais la structure de ton fichier.
Bon, si le fait de dire qu'il y a un mot séparé par un espace ou tabulation est une atteinte à la sécurité alors ils sont parano ;-)
Ce qui m'interesse c'est le séparateur de champ et quelle colonne tu veux remplacer.
et ca marche super bien
Je ne suis pas convaincu.
Ta commande et ta ligne de fichier font deux.
Je vois dans ta regex entre la 1ère et la 2ème capture un deux-point mais pas dans la ligne de ton fichier.
c'est normale que ca marche ou c'est un coup de chance et ca va pas marcher tout le temps ?
Ce que j'ai besoin ce n'est pas le contenu mais la structure de ton fichier.
Bon, si le fait de dire qu'il y a un mot séparé par un espace ou tabulation est une atteinte à la sécurité alors ils sont parano ;-)
Ce qui m'interesse c'est le séparateur de champ et quelle colonne tu veux remplacer.
et ca marche super bien
Je ne suis pas convaincu.
Ta commande et ta ligne de fichier font deux.
Je vois dans ta regex entre la 1ère et la 2ème capture un deux-point mais pas dans la ligne de ton fichier.
re,
Je vois dans ta regex entre la 1ère et la 2ème capture un deux-point mais pas dans la ligne de ton fichier.
je pense que le if /(.*):(.*)/ est par rapport au fichier .occ non ?
effectivement ils sont paranos ^^ c'est le probleme des grosses multinationnales :/
Ce que j'ai besoin ce n'est pas le contenu mais la structure de ton fichier.
le fichier est constitué de lignes toute de meme structure ... 20 colonnes contenant chacune un mot ( ex : test_53_du_01012011 <- ca c'est UN mot ),
la colonne a modifier c'est la 2eme
quant je l'ouvre avec un "more" j'ai l'impression que le séparateur de colonne est une tabulation .
j'espère avoir rrépondu a ta question ... si tu veux d'autres infos hésite pas j'essérai de repondre au mieu...
par contre pour les ":" je n'ai jamais eu de ":" dans mon fichier a traiter.
thx ;)
Je vois dans ta regex entre la 1ère et la 2ème capture un deux-point mais pas dans la ligne de ton fichier.
je pense que le if /(.*):(.*)/ est par rapport au fichier .occ non ?
effectivement ils sont paranos ^^ c'est le probleme des grosses multinationnales :/
Ce que j'ai besoin ce n'est pas le contenu mais la structure de ton fichier.
le fichier est constitué de lignes toute de meme structure ... 20 colonnes contenant chacune un mot ( ex : test_53_du_01012011 <- ca c'est UN mot ),
la colonne a modifier c'est la 2eme
quant je l'ouvre avec un "more" j'ai l'impression que le séparateur de colonne est une tabulation .
j'espère avoir rrépondu a ta question ... si tu veux d'autres infos hésite pas j'essérai de repondre au mieu...
par contre pour les ":" je n'ai jamais eu de ":" dans mon fichier a traiter.
thx ;)
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
8 févr. 2011 à 16:11
8 févr. 2011 à 16:11
Re,
je pense que le if /(.*):(.*)/ est par rapport au fichier .occ non ?
Tu as raison. Je suis au boulot aussi ;-)
Oublie ce que j'ai dit ;-)
Je vais regarder ce soir.
je pense que le if /(.*):(.*)/ est par rapport au fichier .occ non ?
Tu as raison. Je suis au boulot aussi ;-)
Oublie ce que j'ai dit ;-)
Je vais regarder ce soir.
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 567
9 févr. 2011 à 18:00
9 févr. 2011 à 18:00
Salut,
La ligne que tu as modifié est correcte et sur les lignes de type que tu as montré ça marche.
En fait dans mon exemple je faisait le remplacement sur la 3ème colonne et tu veux sur la 2ème.
Normalement \s est une classe de caractères qui inclut la tabulation donc le \t
Tu voulais aussi une explication pour le .*?
Je t'ai donné un exemple ici https://forums.commentcamarche.net/forum/affich-20734055-selection-ligne-suivante-csh-foreach#50
Attention toutefois ce que tu vas utliser comme regex au lieu de modification.
Teste ça
Pour voir encore ce qui ça fait .* au lieu de .*?
Tu peux tester avec
La ligne que tu as modifié est correcte et sur les lignes de type que tu as montré ça marche.
En fait dans mon exemple je faisait le remplacement sur la 3ème colonne et tu veux sur la 2ème.
Normalement \s est une classe de caractères qui inclut la tabulation donc le \t
Tu voulais aussi une explication pour le .*?
Je t'ai donné un exemple ici https://forums.commentcamarche.net/forum/affich-20734055-selection-ligne-suivante-csh-foreach#50
Attention toutefois ce que tu vas utliser comme regex au lieu de modification.
Teste ça
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s.*?\s(.*)/$1\t$h{$1}\t$2/ and print' texte.txt.occ texte.tmp.3_2 > resultat
Pour voir encore ce qui ça fait .* au lieu de .*?
Tu peux tester avec
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s.*\s(.*)/$1\t$h{$1}\t$2/ and print;print "\n"' texte.txt.occ texte.tmp.3_2 > resultat2
2 févr. 2011 à 16:24
Par contre j'arrive pas a le mettre en CSH :/ sachant que l'option -i de sed ne fonctionne pas en CSH :/
si quelqu'un connait le CSH et peu m'aider ? ( encore merci zipe31 )