# Passage d'un tableau associatif bash vers awk

**URL:** <https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383>\
**Category:** Programmation\
**Tags:** bash, awk\
**Created:** [Septembre 21, 2021, 9:15 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383 "2021-09-21T09:15:28Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Lomic](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/l/df705f/32.png) [@Lomic](https://www.debian-fr.org/u/Lomic)\
**Post date:** [Septembre 21, 2021, 9:15 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/1 "2021-09-21T09:15:28Z")

</div>

Voilà mon besoin est tout simple mais sa résolution pas si simple :

- j’ai un fichier csv, fic1.csv, au format date,heure,id
- j’ai un 2nd fichier csv, fic2.csv, au format id, desc

Et je voudrais faire un peu comme en sql une jointure, c’est à dire avoir un nouveau fichier csv de la forme  
date,heure,id, desc

A noter que fic1 fait des centaines de milliers de lignes, alors que fic2 a quelques dizaines de lignes.

Je voudrais faire la chose suivante dans un script shell :

- je charge fic2 dans un tableau associatif tab
- je passe tab comme parametre d’appel a awk
- awk parse fic1 et dès qu’il rencontre un id présent dans tab, il ajoute la description

J’aimerais pouvoir faire ça mais d’après mes premières recherches j’ai l’impression que ça n’est pas trop possible ou alors pas de cette manière.

A noter que j’ai tenté une autre façon de faire mais qui est très très lente :  
dans awk j’ai créé une fonction qui dans un appel systeme fait un grep dans fic2, ça marche mais c’est lourd et surtout très lent.

Merci pour vos lumières.  
Lomic

---

<div class="post-metadata">

**Author:** ![Lomic](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/l/df705f/32.png) [@Lomic](https://www.debian-fr.org/u/Lomic)\
**Post date:** [Septembre 21, 2021, 9:20 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/2 "2021-09-21T09:20:25Z")

</div>

j’oubliais de dire : même si ça n’est pas très propre, je me demandais si le plus simple et le plus performant ne serait pas que j’initialise en dur dans awk un tableau associatif qui contiendrait le contenu de fic2.  
En fait fic2 n’est pas figé, je l’ai créé exprès pour mon besoin mais c’est flexible.

---

<div class="post-metadata">

**Author:** ![Sputnik93](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/s/35a633/32.png) [@Sputnik93](https://www.debian-fr.org/u/Sputnik93)\
**Post date:** [Septembre 27, 2021, 11:53 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/3 "2021-09-27T11:53:53Z")

</div>

Salut,

peut-être qu’il n’est pas utile de passer par un tableau ?

J’ai bricolé vite fait un petit quelque chose pour l’exercice:

```auto
sputnik@debian:~/tests$ cat fic1.csv
2021-09-27,13:28,01
2021-09-27,13:27,02
2021-09-27,13:26,03
2021-09-26,13:25,02
sputnik@debian:~/tests$ cat fic2.csv
01,"premier item"
02,"deuxième item"
03,"troisième item"
sputnik@debian:~/tests$ cat script.sh
#!/bin/bash

# récupérer les id dans fic1.csv
for id in $(awk -F"," '{print $3}' fic1.csv) ; do
        echo -n "$id: "
        awk -v id="$id" -F"," '$0~id {print $2}' fic2.csv
done
sputnik@debian:~/tests$ ./script.sh
01: "premier item"
02: "deuxième item"
03: "troisième item"
02: "deuxième item"

```

Si tu veux faire une jointure, tu peux avoir quelque chose comme ça:

```auto
#!/bin/bash

# récupérer les id dans fic1.csv
for id in $(awk -F"," '{print $3}' fic1.csv) ; do
        echo -n $(awk -v id="$id" -F"," '$0~id {print $1","$2","$3","}' fic1.csv)
        awk -v id="$id" -F"," '$0~id {print $2}' fic2.csv
done

```

Mais ça marche mal avec des id qui sont présents plusieurs fois dans fic1:

```auto
./script.sh
2021-09-27,13:28,01,"premier item"
2021-09-27,13:28,01, 2021-09-27,13:27,02, 2021-09-27,13:26,03, 2021-09-26,13:25,02,"deuxième item"
2021-09-27,13:26,03,"troisième item"
2021-09-27,13:28,01, 2021-09-27,13:27,02, 2021-09-27,13:26,03, 2021-09-26,13:25,02,"deuxième item"

```

---

<div class="post-metadata">

**Author:** ![anon29980398](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/a/f4b2a3/32.png) [@anon29980398](https://www.debian-fr.org/u/anon29980398)\
**Post date:** [Septembre 27, 2021, 4:25 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/4 "2021-09-27T16:25:43Z")

</div>

Bonjour

Une autre approche qui va utiliser le shell `bash` et la commande `sed`  
pour rechercher/remplacer dans une copie du fichier (ou directement dans le fichier à modifier).

```nohighlight
michel@debbull:~/tests$ cat fic1.csv
2021-09-27,13:28,01
2021-09-27,13:27,02
2021-09-27,13:26,03
2021-09-26,13:25,02
michel@debbull:~/tests$ 

```

```nohighlight
michel@debbull:~/tests$ cat fic2.csv
01,"premier item"
02,"deuxième item"
03,"troisième item"
michel@debbull:~/tests$ 

```

Je lance la suite de lignes de commande suivante :

```auto
cp fic1.csv fic3.csv
sep=","
while read ligneId; do
    numId=${ligneId%%$sep*}
    sed -i "s/$sep$numId$/$sep$ligneId/" fic3.csv
done < fic2.csv

```

Et le résultat est :

```nohighlight
michel@debbull:~/tests$ cat fic3.csv
2021-09-27,13:28,01,"premier item"
2021-09-27,13:27,02,"deuxième item"
2021-09-27,13:26,03,"troisième item"
2021-09-26,13:25,02,"deuxième item"
michel@debbull:~/tests$ 

```

* * *

Bien sûr, on peut se passer de faire une copie du fichier  
et faire la modification directement dans `fic1.txt`  
ce qui fait que la suite de lignes de commande devient :

```auto
sep=","
while read ligneId; do
    numId=${ligneId%%$sep*}
    sed -i "s/$sep$numId$/$sep$ligneId/" fic1.csv
done < fic2.csv

```

---

<div class="post-metadata">

**Author:** ![Almtesh](https://www.debian-fr.org/user_avatar/www.debian-fr.org/almtesh/32/10312_2.png) [@Almtesh](https://www.debian-fr.org/u/Almtesh)\
**Post date:** [Septembre 28, 2021, 5:08 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/5 "2021-09-28T05:08:00Z")

</div>

> [@Lomic](#):
>
> Voilà mon besoin est tout simple mais sa résolution pas si simple :
> 
> - j’ai un fichier csv, fic1.csv, au format date,heure,id
> - j’ai un 2nd fichier csv, fic2.csv, au format id, desc
> 
> Et je voudrais faire un peu comme en sql une jointure, c’est à dire avoir un nouveau fichier csv de la forme  
> date,heure,id, desc

Tu as oublié de préciser si les id de fic1.csv sont tous dans fic2.csv. Si ce n’est pas le cas, il faut que la moulinette prenne en compte le fait qu’on peut se retrouver avec une description vide.

> [@Lomic](#):
>
> A noter que j’ai tenté une autre façon de faire mais qui est très très lente :  
> dans awk j’ai créé une fonction qui dans un appel systeme fait un grep dans fic2, ça marche mais c’est lourd et surtout très lent.

Généralement, quand j’évoque un code déjà produit dans la section « Programmation » de ce forum, je le mets dans mon message. Il ne faut pas en avoir honte, si ça se trouve, il n’y a pas grand chose à modifier pour obtenir le bon résultat.

> [@Lomic](#):
>
> je me demandais si le plus simple et le plus performant ne serait pas que j’initialise en dur dans awk un tableau associatif qui contiendrait le contenu de fic2.

Probablement, l’accès aux variables est plus rapide que l’ouverture de fichiers. Par contre, je ne sais pas comment tu veux faire ça, à voir donc si c’est plus simple.

---

<div class="post-metadata">

**Author:** ![Lomic](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/l/df705f/32.png) [@Lomic](https://www.debian-fr.org/u/Lomic)\
**Post date:** [Septembre 28, 2021, 7:45 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/6 "2021-09-28T07:45:21Z")

</div>

Merci pour vos réponses qui effectivement sont intéressantes et permettent de résoudre le pb de façon élégante.

---

<div class="post-metadata">

**Author:** ![Lomic](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/l/df705f/32.png) [@Lomic](https://www.debian-fr.org/u/Lomic)\
**Post date:** [Septembre 28, 2021, 9:00 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/7 "2021-09-28T09:00:20Z")

</div>

Ouais ta résolution est intéressante, pour corriger le pb je me demande s’il ne faut pas tout simplement inverser les boucles; je m’explique : dans un premier tu itères sur fic2.csv et tu récupères tous les ids et ensuite tu itères sur fic1.csv.  
J’ai repris ton script et je l’ai transformé, ça donne :

```
#!/bin/bash

# récupérer les id dans fic2.csv
for id in $(awk -F"," '{print $1}' fic2.csv) ; do
	desc=$( awk -v id="$id" -F"," ' $1 ~ id {print $2} ' fic2.csv)
    awk -v id="$id" -v description="$desc" -F"," '$3 ~ id {print $1","$2","$3","description}' fic1.csv
done

```

Et ça marche bien, à ceci près que l’ordre chronologique n’est pas respecté, ça donne :

> 2021-09-27,13:28,01,«&nbsp;premier item&nbsp;»  
> 2021-09-27,13:27,02,«&nbsp;deuxième item&nbsp;»  
> 2021-09-26,13:25,02,«&nbsp;deuxième item&nbsp;»  
> 2021-09-27,13:26,03,«&nbsp;troisième item&nbsp;»

Mais avec un sort, ça résout le pb.  
En tout cas merci pour le temps que tu as passé sur mon pb 😉

---

<div class="post-metadata">

**Author:** ![Lomic](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/l/df705f/32.png) [@Lomic](https://www.debian-fr.org/u/Lomic)\
**Post date:** [Septembre 28, 2021, 9:04 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/8 "2021-09-28T09:04:05Z")

</div>

Effectivement, encore plus direct et simple, merci.

---

<div class="post-metadata">

**Author:** ![Sputnik93](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/s/35a633/32.png) [@Sputnik93](https://www.debian-fr.org/u/Sputnik93)\
**Post date:** [Septembre 28, 2021, 12:25 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/9 "2021-09-28T12:25:34Z")

</div>

> [@anon29980398](#):
>
> Bien sûr, on peut se passer de faire une copie du fichier  
> et faire la modification directement dans `fic1.txt`

Pas forcément, si tu enlèves l’option `-i` du sed, fic1.txt n’est pas modifié, les substitutions sont juste affichées sur la sortie standard (du coup pas besoin de fic3)

---

<div class="post-metadata">

**Author:** ![anon29980398](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/a/f4b2a3/32.png) [@anon29980398](https://www.debian-fr.org/u/anon29980398)\
**Post date:** [Septembre 28, 2021, 12:54 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/10 "2021-09-28T12:54:39Z")

</div>

> [@Sputnik93](#):
>
> … si tu enlèves l’option `-i` du sed, fic1.txt n’est pas modifié, les substitutions sont juste affichées sur la sortie standard …

> [@Lomic](#):
>
> … A noter que fic1 fait des centaines de milliers de lignes, …

Et comme il y aura autant de lancements de la commande `sed`  
que de lignes dans `fich2`, ça va faire énormément de lignes à afficher.

---

<div class="post-metadata">

**Author:** ![benv13](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/b/ecb155/32.png) [@benv13](https://www.debian-fr.org/u/benv13)\
**Post date:** [Janvier 10, 2022, 3:00 UTC](https://www.debian-fr.org/t/passage-dun-tableau-associatif-bash-vers-awk/85383/11 "2022-01-10T15:00:48Z")

</div>

Hello,  
Dans ta question, tu suggères une des réponses les plus simples à mon avis, faire une jointure SQL.  
SQlite me semble adapté et c’est léger à installer.

```auto
sqlite3 -csv :memory: "create table fic1 (date, heure, id);" "create table fic2 (id, desc);" ".import fic1.csv fic1" ".import fic2.csv fic2" "select fic1.id, date, heure, desc from fic1 join fic2 using (id);"

```
