ajouter un mot en début de ligne par rapport à la valeur cherchée - Codes et scripts - Linux et OS Alternatifs
Marsh Posté le 21-12-2007 à 11:06:21
En awk :
#!/usr/bin/awk -f |
Marsh Posté le 21-12-2007 à 11:32:29
dans votre exemple, le fichier texte source s'appelle type ? si "non" comment j'applique le script au dit fichier.
J'ai besoin de chercher dans la colonne 3 des valeurs qui s'y balade, et non un chaine précise et répétitive de caractère.
si votre script peut être accompagné de quelques explications succintes, cela m'aidera à mieux comprendre
Marsh Posté le 21-12-2007 à 11:45:13
tabasko a écrit : [...] L'action serait :
|
Pas optimisé mais sous cette forme tu devrais comprendre :
#!/bin/sh # lire les lignes une par une # extraire la valeur numérique, ou "Autre" si ca échoue # écrire la ligne done < fichier.txt |
Marsh Posté le 21-12-2007 à 12:09:42
Merci, je comprends la logique
Cela dit, mon exemple reste trop simpliste par rapport à mon besoin réel.
Voici donc un échantillon tronqué de mon fichier source :
None | Unknown | 5076 | None-TOTO-800 | 01/11/07 | 30/11/07 | 0
None | Unknown | 5077 | None-TOTO-800 | 01/11/07 | 30/11/07 | 537
None | Unknown | 5078 | None-TITI-800 | 01/11/07 | 30/11/07 | 1
None | Unknown | 5079 | None-GROUP1-800 | 01/11/07 | 30/11/07 | 2
None | Unknown | 5076 | None800_GROUP2 | 01/11/07 | 30/11/07 | 4
None | Unknown | 5077 | None_GROUP_-800 | 01/11/07 | 30/11/07 | 537
None | Unknown | 5078 | None-GROUP1-800 | 01/11/07 | 30/11/07 | 10
None | Unknown | 5079 | None-ITA-800 | 01/11/07 | 30/11/07 | 22
je souhaite obtenir :
TOTO | None | Unknown | 5076 | None-TOTO-800 | 01/11/07 | 30/11/07 | 0
TOTO | None | Unknown | 5077 | None-TOTO-800 | 01/11/07 | 30/11/07 | 537
TITI | None | Unknown | 5078 | None-TITI-800 | 01/11/07 | 30/11/07 | 1
GROUP1 | None | Unknown | 5079 | None-GROUP1-800 | 01/11/07 | 30/11/07 | 2
GROUP2 | None | Unknown | 5076 | None800_GROUP2 | 01/11/07 | 30/11/07 | 4
GROUP | None | Unknown | 5077 | None_GROUP_-800 | 01/11/07 | 30/11/07 | 537
GROUP1 | None | Unknown | 5078 | None-GROUP1-800 | 01/11/07 | 30/11/07 | 10
Autre | None | Unknown | 5079 | None-ITA-800 | 01/11/07 | 30/11/07 | 22
Les | sont juste ici pour une lecture plus facile des tabulations.
Marsh Posté le 21-12-2007 à 12:20:39
Ben c'est quoi ton motif :
'N'importe quoi' 'tiret et/ou underscore' 'N'importe quoi' 'tiret et/ou underscore' 'N'importe quoi' ?
Parce que matcher ca et en garder un seul morceau c'est pas bien dur
Marsh Posté le 21-12-2007 à 12:53:12
J'ai moins de 10 motifs.
Ils sont délimités par des "-" ou "_" .... Je préfères néanmoins fonctionner avec une liste de motifs précis en les recherchant ligne par ligne, car certains motifs seront regroupés ... (par exclusion du reste (else)).
Merci de votre temps et de votre aide.
Marsh Posté le 21-12-2007 à 14:08:07
tabasko a écrit : dans votre exemple, le fichier texte source s'appelle type ? si "non" comment j'applique le script au dit fichier. |
Comme toute commande unix qui se respecte, elle prend le nom de fichier en argument, ou bien elle lit sur stdin. Bref, deux façons de la lancer (en supposant que tu l'appelles "script.awk", et que ton fichier soit appelé "fichier" ) :
./script.awk fichier |
Ou bien :
./script.awk < fichier |
Ou évidemment toutes les variantes :
cat fichier | ./script.awk |
tabasko a écrit : J'ai besoin de chercher dans la colonne 3 des valeurs qui s'y balade, et non un chaine précise et répétitive de caractère. |
Ah OK j'avais pas compris ça comme ça. Tu as plusieurs valeurs possibles pour la colonne 3, tu ne les connais pas à l'avance, et tu veux donc générer les "type1", "type2" ... "typeN" dynamiquement, c'est ça ? Rien de plus simple, toujours en awk :
#!/usr/bin/awk -f |
Explications : chaque bloc d'un script awk (là il n'y en a qu'un) est exécuté pour chaque ligne lue en entrée (cad chaque ligne de ton fichier). $0 représentes la ligne complète. $1 est la première colone de la ligne en cours, $2 est la deuxième colone, $3 est la troisième colone, etc. Dans ce script "type" est un tableau, qui sont en fait des hash en awk (il n'y a pas de "vrai" tableau, tous les tableaux sont indexés par des chaines de caractère en awk, pas par des nombres). Ce tableau sert à associer, pour chaque type lu en colone 3, le nom de ce type. Donc c'est super simple : pour chaque ligne du fichier, on regarde la 3ème colone. Si c'est la première fois qu'on rencontre ce type, on incrémente "ntypes" (nombre total de types), et on nomme ce type "typeN", où N est ntypes. Dans tous les cas, on affiche la ligne complète ($0) précédée par le nom du type, qu'on a rangé dans le tableau "type" (type[$3]).
Marsh Posté le 21-12-2007 à 14:35:23
tabasko a écrit : J'ai moins de 10 motifs. |
Sauf que dans ton exemple ya un "None_GROUP_-800" (donc - et _) Et aussi un "None800_GROUP2" (donc rien après le groupe)
Si c'est toujours un - ou un _, et qu'il y a toujours 3 morceaux c'est très simple.
Si jamais ca peut être "les 2, voire parfois de temps en temps une virgule, en fait un peu n'importe quoi mais on reconnait bien le groupe non ?" c'est totalement imprécis et peu adapté au traitement (ca se sent que j'ai l'habitude de parser dla merde non ? )
Si on se limite à ton exemple, ca fait :
un nombre quelconque de lettres minuscules ou majuscules, ou de chiffres :
[a-zA-Z0-9]\+
au moins un délimiteur (parfois deux), en tout cas toujours - ou _ :
[-_]\+
un nombre quelconque de lettres minuscules ou majuscules, ou de chiffres :
[a-zA-Z0-9]\+
ce coup-ci le délimiteur peut ne pas être là (s'il manque le 3ème morceau)
[-_]*
le troisième morceau, qui donc peut ne pas être là :
[a-zA-Z0-9]*
Au final :
[a-zA-Z0-9]\+[-_]\+[a-zA-Z0-9]\+[-_]*[a-zA-Z0-9]*
Et on veut garder seulement le morceau du milieu, donc on lui met des parenthèses autour, \( et \), et dans sed on rappelera ce morceau avec \1
[a-zA-Z0-9]\+[-_]\+\([a-zA-Z0-9]\+\)[-_]*[a-zA-Z0-9]*
Est-ce que ca marche sur ton échantillon ? Oui :
for i in None-TOTO-800 None-TOTO-800 None-TITI-800 None-GROUP1-800 None800_GROUP2 None_GROUP_-800 None-GROUP1-800 None-ITA-800; do |
=>
TOTO |
Est-ce que ca marchera sur tout ? Aucune idée, il FAUT que tu définisses clairement TOUT ce qui peut être dans cette colonne 3
Marsh Posté le 21-12-2007 à 15:04:47
ce qui est en colones 4 changera tout les mois.
au risque de me répéter dans un soucis de clareté ... j'ai besoin de faire ce script avec du conditionel.
"si le champ 4 contient le mot TOTO, rajouter le mot toto en début de ligne"
J'en aurai moins de 10 à définir .... en revanche il existe un nombre infini de combinaison possible pour les valeurs qui tomberont dans la colonne 4 (et/mais toujours contiendra l'un des 10 motifs clefs).
Désolé si je m'exprime mal.
Merci pour les efforts mis en oeuvre.
Xavier, merci aussi pour vos notes précieuses que j'archive pour d'autre usage futur.
Marsh Posté le 21-12-2007 à 15:09:04
tabasko a écrit : ce qui est en colones 4 changera tout les mois. |
Si on prend mon premier script, qu'on remplace 3 par 4, et qu'on remplace l'extraction de la valeur numérique par le "echo | sed blablabla" de mon dernier message, on obtient bien un script qui rajoute TOTO si le champ 4 contient TOTO
Marsh Posté le 21-12-2007 à 15:29:48
Xavier, je m'y perds..................
#!/bin/sh
# lire les lignes une par une
while read line; do
# récupérer le champ 4
F4=$(echo "${line}" | cut -d ' ' -f 4)
# extraire la valeur numérique, ou "Autre" si ca échoue
#NUM=$( (echo "${F3}" | grep -o '[0-9]') || (echo "Autre" ) )
NUM=$(echo "${i}" | sed 's/[a-zA-Z0-9]\+[-_]\+\([a-zA-Z0-9]\+\)[-_]*[a-zA-Z0-9]*/\1/')
# écrire la ligne
echo "Type${NUM} ${line}"
done < fichier.txt
Marsh Posté le 21-12-2007 à 15:37:34
je viens d'essayer et cela me rajouter "Type" en début de chaque ligne.
donc maintenant, et cela m'échappe encore, à quel endroit je vais placer ma dizaine de motifs .... il est ou l'egrep ?
Pareil, me tapez pas dessus $i il sort d'où Xavier ?
Merci.
Marsh Posté le 21-12-2007 à 15:47:38
tabasko a écrit : je viens d'essayer et cela me rajouter "Type" en début de chaque ligne. |
c'est F3F4
Marsh Posté le 21-12-2007 à 15:55:20
bien. et quant à ma première question , l'association des termes (entre celui que je cherche et celui qui va devenir mon motif de début de ligne) je le place ou dans le script ?
De là à ce que vous me répondiez, j'essaye de comprendre péniblement dès fois que j'y arrive
Marsh Posté le 21-12-2007 à 16:01:31
Nulle part,
NUM=$(echo "${F4}" | sed 's/[a-zA-Z0-9]\+[-_]\+\([a-zA-Z0-9]\+\)[-_]*[a-zA-Z0-9]*/\1/') |
"détecte" dans la colonne 4 le motif à mettre en début de ligne et le stock dans NUM.
Pas besoin de prédéfinir une liste de motifs à chercher, cette expression régulière les trouvera à partir du moment où on a bien :
blablabla, puis - ou _, puis blablabla, puis - ou _, puis blablabla (avec les précautions expliquées précedemment quand au troisième morceau qui apparement n'est pas toujours là)
Si on veut prédéfinir une liste on peut, mais donc sur chaque ligne on va tester tous les motifs jusqu'à trouver celui qui va bien, c'est pas mal plus long du coup comme traitement (et c'est pas tout à fait le même script évidemment ).
Marsh Posté le 21-12-2007 à 16:04:20
Xavier, comme vous avez le temps de détailler vos réponses, j'ai pris le temps de les relire, et je comprends que dans l'état cela devrait fonctionner, et c'est exactement ce que je cherche à faire.
Par contre cela ne fonctionne pas ...
Dans mon échantillon j'ai des mentions de type "None-TITI-800" et en début de ligne le script ne me sort que le mot "Type".
Ou est ce que j'ai pu me tromper ? pourrait ce être une histoire de délimiteur mal interprété ???
Citation : #!/bin/sh |
Marsh Posté le 21-12-2007 à 16:07:46
nos derniers messages se sont croisés.
merci pour votre explication, c'est ce que j'ai compris en effet en vous relisant.
En sortie, malgré cela, je n'obtiens toujours que "Type" et à aucun moment les valeurs comprises entre les "-".
Je viens de faire une recherche des valeurs existantes en colonnes 4 ... j'en ai pas mal avec 3 x "-" ...
genre : blabla-TOTO-titi-800 , c'est toto qui m'intéresse, le présent code ne pourra pas dissocier le TOTO du titi ... non ?
Marsh Posté le 21-12-2007 à 16:11:08
tabasko a écrit : nos derniers messages se sont croisés. |
Ah oui, si parfois on a 4 morceaux et que le morceau à garder peut être le 2 ou le 3 selon les cas, il n'y a pas de solution (enfin si mais ca devient un peu sportif).
Il faut donc bien préparer une liste des mots à détecter en colonne 4, et pour chaque ligne tester un par un ces mots pour voir lequel est présent
Marsh Posté le 21-12-2007 à 16:19:27
1/ je vois pas ou je place ma recherche condition de mot à tester , pourriez vous me mettre sur le chemin? (1 exemple avec TOTO m'irait bien)
2/ cut -d ' ' -f 4) = le séparteur retenu est l'espace ou la tabulation avec cette syntaxe ?
Merci
Marsh Posté le 21-12-2007 à 16:47:19
tabasko a écrit : 1/ je vois pas ou je place ma recherche condition de mot à tester , pourriez vous me mettre sur le chemin? (1 exemple avec TOTO m'irait bien) |
1)
à la place de
# extraire le motif dans F4, ou "Autre" si ca échoue |
il faut mettre une boucle du genre :
# test une par une les valeurs prédéfinies jusqu'à trouver un truc dans F4 |
2) man cut pour consulter le manuel (de base c'est tabulation, mais là avec "-d ' '" je précise que je veux un espace pour délimiteur)
Marsh Posté le 21-12-2007 à 17:29:55
je suis pas certain qu'il vérifie de condition (malgré le -q d'après ce que j'ai compris qui stop le grep )....
en sortie, il ne me donne pour ${mot} que la dernière entrée que j'ai communiquée.... (par rapport à mon ex, TUTU).
Citation : #!/bin/sh |
Xavier, je pense que je vais un peu décrocher pour le moment, je répondrai les soirs tards, ou lundi ...
Encore merci pour le temps et les précisions que vous m'avez communiquées.
Marsh Posté le 21-12-2007 à 18:25:57
tabasko a écrit : je suis pas certain qu'il vérifie de condition (malgré le -q d'après ce que j'ai compris qui stop le grep )....
|
La boucle et le if permettent de mettre le bon mot (et uniquement le bon mot) dans $PREFIX
Il faut donc faire à la fin echo "${PREFIX} ${line}" (et non plus $mot)
Marsh Posté le 24-12-2007 à 10:38:37
Merci XAVIER !!! ca commence à tourner !!!!
comment cela se passe pour les termes recherchés (for mot in TATA TOTO TITI TUTU; do ) si un champs en contient deux d'entre eux.
Le script se contentera-t-il de prendre le premier des deux qu'il rencontre pour s'en servir comme préfixe.
En d'autre terme, lorsque la condition est vérifiée, il ne continue pas à vérifier les termes suivants ?
(j'ai besoin de cela car dans l'état, il ne gère pas les exclusions : à savoir, prefix=autre, si pas TATA TOTO TITI TUTU.
Merci encore...
Marsh Posté le 24-12-2007 à 11:21:29
j'ai pas l'impression qu'il m'extracte proprement la colonne 4
de même lorsque j'applique cut -d ' ' -f 4 à mon fichier texte source, je n'obtiens pas un extract de la colonne 4, normal ?
j'ai essayé sans succès de placer dans le script un awk '{print$4}' qui est la syntaxe que j'ai l'habitude d'utiliser pour extraire une colonne....
-edition perso-> je retire le "-d" ce qui remet le séparateur à tabulation à la place de l'espace, cela règle le problème d'lextraction.
me reste donc à gérer l'exclusion ....
mon script définit les termes rechercher dans un fichier "TYPE.txt".
Si aucun des termes listés n'est trouvé, j'aimerai faire de PREFIX ; le mot "autre".
je trouve pas comment placer mon else.
Marsh Posté le 24-12-2007 à 14:49:50
Citation : #!/bin/sh |
Ceci fonctionne comme désiré, mais reste des exceptions qui font défaut à l'application du script.
J'ai refais mon fichier (motif) TYPE de manière à ce que la première colonne soit la valeur que je recherche, et la seconde, celle dont je souhaite me servir pour le préfixe.
En gros ... et cela ne marche pas je voudrai faire :
Citation : #!/bin/sh |
Ceci ne fonctionne pas, et je tourne en rond ... Merci d'avance à ceux qui pourraient m'aider !
Marsh Posté le 21-12-2007 à 10:25:41
Bonjour à tous !
Je cherche à faire un script, mais manifestement il me manque un peu de connaissance pour y parvenir.
Je dois lire un gros fichier ligne par ligne, et en fonction du contenu d'une colonne (dans mon exemple, la colonne 3), je voudrai rajouter un mot précis en début de ligne.
L'action serait :
Par exemple si mon fichier original est :
AAA BBB CC1 DDD EEE FFF GGG
AAA BBB C2C DDD EEE FFF GGG
AAA BBB 3DD EEE FFF GGG HHH
AAA BBB CCC EEE FFF GGG HHH
En sortie je voudrai être capable d'obtenir :
Type1 AAA BBB CC1 DDD EEE FFF GGG
Type2 AAA BBB C2C DDD EEE FFF GGG
Type3 AAA BBB 3DD EEE FFF GGG HHH
TypeAutre AAA BBB CCC EEE FFF GGG HHH
PS : les valeurs que je cherche dans la colonne 3 (et dont dépend le mot rajouté en début de chaque ligne) peut varier et la structure du champs n'est pas forcement homogène (je peux chercher un jeu de 4 caractères par exemple, mais pas forcement situé au même endroit dans la chaine caratères (mais toujours dans la même colonnes).
J'ai essayer de faire une boucle pour lire sans succès, puis me suis pencher un peu sur sed .
Je suis en misère.
Merci à ceux qui prendront le temps de m'aider.