Bonjour,
Je suis très novice dans le monde linux.
Je cherche à remplacer une chaine de caractères dans plusieurs fichiers texte (+de 5000)
Ces fichiers sont générés par des machines de test, ils comportent 1 seule ligne.
La chaine à chercher est présente dans plusieurs fichiers ( 1 fichier par erreur rencontrée )
la chaine de remplacement est dans un fichier de type Liste.csv
Chaine1;Remplace1
Chaine2;Remplace2
Chaine3;Remplace3
Chaine4;Remplace4
Chaine5;Remplace5
...
Chainex;Remplacex
Sous Shell, si je lance le grep plusieurs fois de suite
j'ai le retour de la ligne voulue à chaque fois que je lance
grep -n Chaine1 Liste.csv
Dans un script AWK la même commande donne un résultat différent.
je récupère le résultat du grep dans une variable awkgrep -n ^Chaine1 Liste.csv | getline VariableAwk
Et la problème …
Seule la 1ère recherche donne un résultat.
si chaine1 est cherché une 2ème, 3ème fois, la variable reste vide.
Il semble que le grep ne lise qu'une fois le fichier Liste.csv
la 1ere fois il trouve la chaine en ligne 2,
la fois suivante, la recherche commence à la ligne 3 et donc ne trouve pas de correspondance.
Pouvez vous m'aider à résoudre ce problème
merci
EDIT
La syntaxe du script peut paraitre bizarre, mais pauvre de moi,
je suis sous MS-DOS avec les commandes GnuWin32.
les " et les ' n'ont pas tout à fait la même signification qu'avec un vrai shell.
c'est la raison des trop nombreux "print commande" du script.
J'ai tester avec la commande SED à la place GREP,
le problème est le même, seule la 1ère recherche est fructueuse,
les autres retournent des variable vides.
La commande lancée est
awk -f Script_Article_From_Liste.awk *.txt
Le script est (plein de "print" pour suivre à l'écran, ils seront supprimés)
BEGIN {
FS=";";
OFS=";";
DATAFILE="Liste_Of-Article-Qty.csv"
SNKEY="M"
SNCNTR=100000
print "----- START AWK -----------------------------------------------------"
print "liste OF - Article : " DATAFILE
}
{
# Lecture 1er fichier
print ""
print "---------------------------------------------------------------------"
print "Fichier : " FILENAME " || " $0
OFNUM=$1
PARTNUM=$2
SERNUM=$8
# Chercher dans le fichier DATAFILE la chaine OFNUM avec Grep
# !!! Ne fonctionne pas si 2 fois le meme OF cherche ...
GREPCMD="GREP -n ^" OFNUM " " DATAFILE
print "COMMANDE : " GREPCMD
GREPCMD | getline DATALINE
print "GREP DATALINE : " DATALINE
# Chercher dans le fichier DATAFILE la chaine OFNUM avec SED
# !!! Ne fonctionne pas si 2 fois le meme OF cherche ...
# le head pour ne garder que la premiere occurence trouvee
# SEDCMD="SED -s -n /" OFNUM "/p;q " DATAFILE | head -n 1"
# print "COMMANDE : " SEDCMD
# SEDCMD | getline DATALINE
# print "DATALINE : " DATALINE
# AJOUTER conditions d'erreurs !!
# DATALINE vide ...
#
# Reformater les separateurs ( grep utilise : au lieu de ; )
# Pas utile si SED utilis‚ … la place de GREP
sub(":",";",DATALINE)
# Changer DATALINE en tableau pour extraire les champs LINE / OF / NEWART / QTY
split(DATALINE,DATATAB)
print "DATATAB : " "(1) " DATATAB[1] " | (2) " DATATAB[2] " | (3) " DATATAB[3] " | (4) " DATATAB[4]
# Creer Numero de serie / Remplacer Code article
SNCNTR=(SNCNTR + 1)
$8=SNKEY SNCNTR "-" $2
$2=DATATAB[2]
PARTNUM=$2
SERNUM=$8
# Ligne Modifiee
print "Fichier : " FILENAME " || " $0
# Ecrire le fichier sur le disque
# print $0 > FILENAME
# Fermer les variables Locales ...
DATALINE=""
DATANUMLINE=""
OFNUM="VIDE"
PARTNUM="VIDE"
SERNUM="VIDE"
delete DATATAB # Vider le tableau pour eviter les effets de bords
close(DATAFILE) # Fermer le fichier pour forcer la lecture depuis le début (ne marche pas!)
}
END{
print ""
print "----- FIN AWK ---------------------------------------------"
print "Fichier(s) lu(s) : " SNCNTR-100000
print "Dernier Numero de serie : " SNKEY SNCNTR
print ""
}
La liste de correspondance est (raccourcie)
No_OF;Article;Qté
1000014645;R8011450;250
5000000882;R7900085;247
1000014433;R800019;140
2000050803;R800020;136
5000000843;R800021;130
Les fichiers à traiter sont
AwkTest_01.txt
5000000882;000176A;sg;130927;105057;AOI_2;0.0.2;1;1;0;;
AwkTest_01b.txt (celui qui n'est pas vu … )
5000000882;000176B;sg;130927;105057;AOI_2;0.0.2;M100002-7654321;1;0;;
AwkTest_02.txtsh
2000050803;000177A;sg;130927;105135;AOI_2;0.0.2;1;1;0;;
# Sed?
Posté par Jiehong (site web personnel) . Évalué à 3.
Pour remplacer une chaîne de caractères dans un fichier, Sed fonctionne bien.
Exemple :
[^] # Re: Sed?
Posté par Olivier (site web personnel) . Évalué à 3.
Je rajoute que la référence pour avoir une idée de ce que "sed" peut faire est
http://sed.sourceforge.net/sed1line_fr.html
Il y a tout un tas d'exemples de trucs simples, pratiques, voir carrément tordus, donc indispensables !
# Besoin de plus de contexte et de clarté
Posté par benoar . Évalué à 3.
Bon, j'ai moyennement compris ton problème, car les explications en français c'est moyen (« lancer plusieurs fois » : pour quelle raison ? avec quels arguments ? pour quel résultat ? ; tu as des fichiers d'une ligne, est-ce qu'ils correspondent à une « erreur » ? c'est quoi ces « erreurs » ?).
Par contre, je peux te dire que c'est contre-productif de faire un grep dans awk : awk a des fonctions intégrées pour ça. Si tu veux faire quelque chose quand une ligne match, fait :
Ensuite, si tu veux faire « simplement » du remplacement, un bon vieux sed marche bien. Ton fichier de chaînes, d'ailleurs, tu pourrais en faire un script sed :
Etc. Et si tu veux vraiment que ça soit un CSV avec point virgule, tu pourrais même l'écrire ainsi :
Et ton fichier tableur devient magiquement un script sed qui fait ce que tu veux.
[^] # Re: Besoin de plus de contexte et de clarté
Posté par ArbreCiré . Évalué à 1.
Merci de ce retour rapide.
Les fichiers d'une lignes sont des rapports d'erreur de machines outils.
Prendre une carte, la tester, à chaque erreur rencontrée écrire un fichier.
Si la carte testée comporte 10 erreurs, il y aura 10 fichiers
avec awk, j'ouvre chaque fichier, j’extraie la 1ere chaine
Je traite ensuite tous les fichiers la contenant ( d'ou le grep )
J'espère avoir été un peu plus clair …
J'ai éditer le 1er post pour y placer les fichier en question.
Merci de l'aide.
[^] # Re: Besoin de plus de contexte et de clarté
Posté par benoar . Évalué à 1.
Bon, je n'ai pas énormément plus compris. Au début tu parles de remplacement mais après tu ne remplaces jamais rien, et puis tu parles de « fichier » pour tes fichiers différents, alors que j'ai identifié au moins deux types différents (ceux, d'une ligne, qui contiennent l'erreur — d'ailleurs, parler de « première ligne » pour un fichier d'une ligne ajoute à la confusion — et celui qui a une tables de correspondance des remplacements).
Ce que je vois, c'est que getline ne te renvoie qu'une ligne, donc oui forcément tu n'as que le premier match du grep/sed invoqué.
En passant, j'ai l'impression que ton but plus général, ça ressemble à une jointure SQL. Si tu veux commencer à faire de la manipulation de donnée un peu avancée, tu ferais peut-être mieux d'importer tout ça en SQL et de créer des requêtes adéquates. Ça sera même plus clair pour toi je pense, au lieu de jouer du shell et des fichiers (c'est bien pour un petit script qui fait une tâche simple, mais ça devient vite limitant).
Bonne chance.
[^] # Re: Besoin de plus de contexte et de clarté
Posté par fearan . Évalué à 2.
Hou la tu veux la mort de DOS toi ;) l'utilitaire join me parait plus approprié ;)
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
[^] # Re: Besoin de plus de contexte et de clarté
Posté par fearan . Évalué à 3.
logique tu n'as pas de boucle ;)
il faudrait plutôt au niveau du getline avoir un
while( ( GREPCMD | getline DATALINE) > 0 )
{
…
}
Je fais ça de tête sans tester, faut peut être mettre le résultat de grep dans une variable intermédiare
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
[^] # Re: Besoin de plus de contexte et de clarté
Posté par anaseto . Évalué à 1. Dernière modification le 03 mars 2014 à 22:33.
Je ne suis pas sûr d'avoir tout compris, mais as-tu essayé ce que disait benoar?
C'est-à-dire quelque chose comme
pour transformer ton fichier Liste.csv en un script sed. Et ensuite utiliser ce script pour faire les substitutions :
# Mes deux centimes
Posté par Marotte ⛧ . Évalué à 4. Dernière modification le 03 mars 2014 à 19:25.
À la lecture de ton post et des commentaires je vais te donner mon avis. Tu le mettras bien entendu à l'endroit de ta convenance !
Jiehong et benoar ont raison. Tu dois utiliser sed, c'est fait, entre-autre, pour ça, remplacer une chaînes par une autre dans un fichier. grep lui, sert à filtrer les lignes d'un fichier selon un motif.
awk est aussi une solution mais c'est sed ou bien awk, je ne crois pas qu'il y ait de cas réels ou théoriques où l'utilisation des deux en même temps dans un pipeline est pertinente. Je pose la question.
fearan a, je pense, touché le nœud de ton problème. Il te manque une boucle !
Par ailleurs,
Il y a une syntaxe qui permet de rendre ton script lisible, utilise la à l'avenir, c'est indispensable lorsque tu colles un script, DOS ou Unix, même la copie des messages d'un terminal.
Bienvenue à toi sur linuxfr.org.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.