Aide sur un script shell
RésoluBonjour,
J'ai essayé d'écrire un script comme suit :
Soit un fichier A avec séparateur ";" que je veux découper en deux fichiers :
- un fichier B qui contient toutes les lignes qui ne commencent pas par "SEP-DOC2"
- un fichier C qui content toutes les lignes qui commencent par "SEP-DOC2"
Ensuite, je voudrais rajouter au bout de chaque ligne du fichier B la ligne correspondant du fichier C (sauf les 3 premier champ) en comparant le champ 2 du fichier B pour qu'il soit identique au champ 3 du fichier C. Le résultat sera mis dans un fichier final.
Voici mon code :
PA=$SIGACS/file/PSMDMSAL.LS PB=$SIGACS/txt/tmp/MDMSAL/PSMDMSAL_B.LS PC=$SIGACS/txt/tmp/MDMSAL/PSMDMSAL_C.LS PD=$SIGACS/txt/tmp/MDMSAL/PSMDMSAL_FINAL.LS export PA echo "$PUCE_INF $PA" >> $FIC_LOG echo "$PUCE_INF Traitement en cours" >> $FIC_LOG grep -v "^SEP-DOC2" $PA > $PB grep "^SEP-DOC2" $PA > $PC while IFS=';' read -r col1_B col2_B rest_B; do line_C=(grep "^SEP-DOC2.*;col2_B;" $PC) if [ -n $line_C ]; then # Extraire les champs après le 3e champ dans la ligne C rest_C=(echo "$line_C" | cut -d ';' -f 4-) # Ajouter cette donnée à la ligne B echo "$line_B$rest_C" else # Si aucune ligne correspondante, afficher la ligne B sans modification echo "$line_B" fi done < $PB > $PD
quand je l'exécute, il me signal qu'il y a un problème de syntaxe sur la ligne rest_C=(echo "$line_C" | cut -d ';' -f 4-) avec le pipe.
Une idée sur ce qui ne va pas ? est ce que vous penser que mon code est correcte ?
Cdt.
Merci d'avance pour votre aide
- Xxxbbbffff
- Classic shell - Télécharger - Personnalisation
- Script vidéo youtube - Guide
- Mas script - Accueil - Windows
- Ghost script - Télécharger - Polices de caractères
- Script cmd - Guide
4 réponses
Bonjour,
Pour commencer je pense que tu n'es pas nul contrairement à ce que ton pseudo suggère, ne te rabaisse pas et crois en toi ;-)
Concernant ton code, le début est bien écrit (avec grep) mais par contre pour la suite tu t'es compliqué la vie, je pense que tu devrais plus simplement utiliser la commande join.
Exemple :
# Les fichiers traités par join doivent être triés au préalable sort /etc/passwd > B.txt sort /etc/group > C.txt # Dans ces fichiers le séparateur est ':' # On fait une jointure sur le premier champ join -1 1 -2 1 -t ':' B.txt C.txt
Dans ton cas, si j'ai bien compris ton énoncé, ça devrait ressembler à ceci :
#!/bin/sh PA="$SIGACS/file/PSMDMSAL.LS" PB="$SIGACS/txt/tmp/MDMSAL/PSMDMSAL_B.LS" PC="$SIGACS/txt/tmp/MDMSAL/PSMDMSAL_C.LS" PD="$SIGACS/txt/tmp/MDMSAL/PSMDMSAL_FINAL.LS" grep -v "^SEP-DOC2" "$PA" | sort > "$PB" grep "^SEP-DOC2" "$PA" | sort > "$PC" join -1 2 -2 3 -t ';' "$PB" "$PC" > "$PD"
Remarque : En shell, veille à entourer tes évaluations de variables de guillemets comme je l'ai fait ci-dessus. C'est important, car si ces variables contiennent des espaces, on peut faire planter le programme voire injecter du code.
Si je n'ai pas répondu à ta question peux-tu partager (quitte à les anonymiser) un extrait minimal du fichier d'entrée à partir duquel on pourra tester ?
Bonne chance
Bonjour,
En réponse à #3,
- Attention car tu ne tries pas (sort) tes fichiers avant de faire le join. Cela signifie que dans le cas général la jointure peut mal se passer.
- Concernant ta question, l'option intéressante est -o (voir cette discussion).
- Au pire tu pourrais utiliser la commande awk. Même si c'est une solution valide, elle n'est pas très performante, car elle revient à mal écrire chaque ligne, puis à les corriger, alors que tu pourrais directement écrire les lignes correctement.
#!/bin/sh PA="A.csv" PB="B.csv" PC="C.csv" PD="D.csv" col_B=4 col_C=2 grep -v "^SEP-DOC2" "$PA" | sort -t ',' -k "$col_B" > "$PB" grep "^SEP-DOC2" "$PA" | sort -t ',' -k "$col_C" > "$PC" format="1.1,1.2,1.3,1.4,1.5,2.1,2.2,2.3,2.4" join -1 "$col_B" -2 "$col_C" -t ',' "$PB" "$PC" -o "$format" > "$PD"
Bonne chance
Bonjour,
Tout d'abord merci pour tes encouragements et c'est grâce à des bonnes âmes comme toi et beaucoup d'autre qui m'ont aidé ici que j'arrive à apprendre un plus peu à chaque fois.
Et merci pour ton aide et tes conseils.
J'ai donc modifié mon code en le simplifiant comme tu me l'as montré. J'arrive à obtenir mon fichier final avec mes lignes correctement concaténées.
J'ai juste un point qu'il me faut régler :
Le champ qui me sert de clé de rapprochement du fichier 1 qui est dans mon cas en position 3 se retrouve une fois la jointure faite en premier position du fichier final alors que je souhaiterais qu'il reste à sa place.
J'ai regardé les options du "Join" mais je n'ai rien vu qui pourrait empêcher cela.
Exemple :
Fichier A (à noter que le premier champ des lignes sans "SEP-DOC2" est vide) :
,XXX,BBB,clé1,FFFF,GGG ,OOO,LLL,clé2,MMMM,AAA SEP-DOC2,clé1,YYYY,III SEP-DOC2,clé2,NNNN,WWW
Découpage en deux fichiers :
PA="A.csv" PB="B.csv" PC="C.csv" PD="D.csv" grep -v "^SEP-DOC2" "$PA" > "$PB" grep "^SEP-DOC2" "$PA" > "$PC" join -1 3 -2 3 -t ',' "$PB" "$PC" > "$PD"
Fichier B :
,XXX,BBB,clé1,FFFF,GGG ,OOO,LLL,clé2,MMMM,AAA
Fichier C :
SEP-DOC2,clé1,YYYY,III SEP-DOC2,clé2,NNNN,WWW
Après la commande "join"
Fichier final :
clé1,,XXX,BBB,FFFF,GGG,SEP-DOC2,clé1,YYYY,III clé2,,OOO,LLL,MMMM,AAA,SEP-DOC2,clé2,NNNN,WWW
Fichier Final souhaité:
,XXX,BBB,clé1,FFFF,GGG,SEP-DOC2,clé1,YYYY,III ,OOO,LLL,clé2,MMMM,AAA,SEP-DOC2,clé2,NNNN,WWW
J'ai essayé avec la commande cut mais pour l'instant, j'obtiens pas vraiment ce que je souhaites.
Merci d'avance si tu as une solution. Je continue à chercher de mon côté.
Bonjour Mamiemando,
Désolé d'avoir tardé à répondre mais j'ai du switcher sur un autre sujet très urgent.
J'ai utilisé la commande -o et je me suis arrangé aussi pour modifier légèrement l'ordre des colonnes du fichier pour simplifier les choses car mon vrai fichier a 60 colonnes.
J'obtiens le résultat souhaité.
Merci encore pour ton aide et tes encouragements.
Merci.
Désolé d'avoir tardé à répondre mais j'ai du switcher sur un autre sujet très urgent.
Pas de soucis, on a tous nos urgences :-)
J'obtiens le résultat souhaité.
Parfait !
Merci encore pour ton aide et tes encouragements.
Je t'en prie, moi aussi on m'a mis le pied à l'étrier à mes débuts. Je ne fais que perpétuer cet héritage ;-)