Aide sur un script shell

Résolu
JsuisNul Messages postés 125 Date d'inscription mercredi 13 février 2013 Statut Membre Dernière intervention 6 mars 2025 - Modifié le 12 févr. 2025 à 12:14
mamiemando Messages postés 33636 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 18 avril 2025 - 6 mars 2025 à 12:25

Bonjour,

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 

A voir également:

4 réponses

mamiemando Messages postés 33636 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 18 avril 2025 7 842
Modifié le 12 févr. 2025 à 12:30

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

1
mamiemando Messages postés 33636 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 18 avril 2025 7 842
Modifié le 18 févr. 2025 à 16:11

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

1
JsuisNul Messages postés 125 Date d'inscription mercredi 13 février 2013 Statut Membre Dernière intervention 6 mars 2025 1
Modifié le 18 févr. 2025 à 15:50

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é. 

0
JsuisNul Messages postés 125 Date d'inscription mercredi 13 février 2013 Statut Membre Dernière intervention 6 mars 2025 1
6 mars 2025 à 10:13

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.

0
mamiemando Messages postés 33636 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 18 avril 2025 7 842
6 mars 2025 à 12:25

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 ;-)

0