logo Debian Debian Debian-France Debian-Facile Debian-fr.org Forum-Debian.fr Debian ? Communautés logo inclusivité

Debian-facile

Bienvenue sur Debian-Facile, site d'aide pour les nouveaux utilisateurs de Debian.

Vous n'êtes pas identifié(e).

#1 18-02-2016 20:53:14

Spirale21
Membre
Distrib. : Debian GNU/Linux 9.12 (stretch)
Noyau : Linux 4.9.0-12-amd64
(G)UI : i3
Inscription : 26-02-2013

[RESOLU] un tableau bash et des indices avec espaces

Bonjour
Mon but est de générer une page HTML en bash. J'ai un fichiers no.txt qui est

John rachid
John Rachid
José Pierre
John Rachid
John Rachid
José Pierre
Xabn
 



donc je fais en bash

declare -a nom;
nom=$(cat no.txt |sort |uniq)



l'ennui c'est qu'il me met

nom=John Rachid José Pierre Xabn donc 5 items

alors que moi je voudrais

nom='John Rachid' 'José Pierre' 'Xabn' donc que 3 items


Je suis partit sur un tableau mais je sais pas si il existe une autre structure. Une solution (que je pensais) serais de passer par un fichiers intermédiaire mais il y a une autre solution? passer par un script awk?
Merci

Dernière modification par Spirale21 (19-02-2016 00:08:32)


La difficulté est source d'apprentissage

Hors ligne

#2 18-02-2016 21:46:03

enicar
Membre
Lieu : pas ici
Distrib. : sid
Noyau : Linux 6.5.3
(G)UI : openbox
Inscription : 26-08-2010

Re : [RESOLU] un tableau bash et des indices avec espaces

Utilise plutôt mapfile en utilisant un fichier temporaire pour
faire le sort. Le uniq n'est pas nécessaire on peut le faire
faire par sort -u. Par exemple, on peut faire  cela :


# On crée le fichier temporaire :
tempfile=$(mktemp no-XXXXXXXXX)

# On trie et « uniquifie »  en redirigeant la sortie vers
# le fichier temporaire
sort -u no.txt >"$tempfile"

# On initialise le tableau :
mapfile -t nom <"$tempfile"
 


Une autre méthode est d'utiliser IFS :


OLD_IFS="$IFS"
# On utilise le caractère nouvelle ligne pour la séparation
# en mots de bash.
IFS=$'\n'

# on initialise le tableau :
nom=( $(sort -u no.txt) )

# On rétablie IFS
IFS="$OLD_IFS"
 


Je pense que l'on peut même faire cela en une seule ligne :


IFS=$'\n' nom=( $(sort -u no.txt) )
 


Dans ce dernier cas IFS est redéfinie localement pour la commande sur
la même ligne. Donc il n'y a pas besoin de la sauvegarder. Ensuite,
IFS reprend sa valeur d'origine. Je n'ai pas testé mais ça devrait
fonctionner. Tu me diras si c'est le cas wink

EDIT: C'est du bash, en sh mapfile n'existe pas il me semble.

Dernière modification par enicar (18-02-2016 21:47:24)

Hors ligne

#3 19-02-2016 00:07:55

Spirale21
Membre
Distrib. : Debian GNU/Linux 9.12 (stretch)
Noyau : Linux 4.9.0-12-amd64
(G)UI : i3
Inscription : 26-02-2013

Re : [RESOLU] un tableau bash et des indices avec espaces

Alors ça marche à moitié... j'ai utilisé la deuxième méthode celle de l'IFS. ça marche mais quand tu rétablit l'IFS le nombre d'arguments dans le tableau est toujours bon mais il affiche pas correctement

for i in ${nom[@]}
do
 echo $1
done


ça fait

John
Rachid
José
Pierre
Xabn


donc soit je rétabli l'IFS en toute fin de mon programme soit je fais une boucle (solution choisie wink )

#attention les indices de tableau commencent à 0
for (( i=0; i<${#nom[@]}; i++ ))
do
 echo -e ${nom[$i]}
done


parce que tu vas pas tout me faire lol big_smile, mais t'es trop fort !!! ça m’énerverai presque mad lol wink
Merci de m'avoir mis sur la bonne voie

Dernière modification par Spirale21 (19-02-2016 00:21:27)


La difficulté est source d'apprentissage

Hors ligne

#4 19-02-2016 00:23:11

enicar
Membre
Lieu : pas ici
Distrib. : sid
Noyau : Linux 6.5.3
(G)UI : openbox
Inscription : 26-08-2010

Re : [RESOLU] un tableau bash et des indices avec espaces

Je viens de m'amuser à faire un autre script qui montre deux solutions
pour initialiser un tableau à partir d'un fichier d'une liste, avec la
contrainte de rendre chaque élément unique comme ce que tu voulais :


#! /bin/bash

display_array(){
    local -n tab=$1
    local -i i=0
    for elt in "${tab[@]}"; do
        echo $i: $elt
        i=$i+1
    done
}

# Première méthode
IFS=$'\n' noms=($(sort -u no.txt))
display_array noms

echo "------------------------------------------------"
# Seconde méthode
IFS=$'\n' read -r -d $'\0' -a noms <<<"$(sort -u no.txt)"
display_array noms
 


Les deux font la même chose, je pense que la première est préférable,
mais c'était juste pour montrer que les possibilités sont nombreuses.

J'ai fait une fonction pour afficher la liste. Ça montre comment
parcourir le tableau élément par élément.  Cette fonction utilise
aussi « local -n » qui permet d'utiliser une référence. « local -n tab=$1 »
va permettre d'utiliser tab comme si c'était le tableau dont le nom
est passé en argument.  Quand on fait : « display_array noms »,
l'argument passé à la focntion est juste la chaine « noms », rien de
plus. Ensuite c'est le « déclare -n » qui fait opérer la magie wink

La seconde méthode est peu plus complexe à comprendre. Le « IFS=$'\n'
permet de faire un découpage de mots avec le caractère '\n' comme
précédemment. Donc quand bash interpole la commande "$(sort -u no.txt)"
la chaine vaut exactement le nombre de ligne renvoyer par « sort -u ».
Ensuite, comme pour le read, un enregistrement se termine par '\n',
je rdéfini ce délimiteur pour utiliser un caractère nul (-d $'\0').
De cette façon, read lit tous les éléments, sinon il ne lirait
que le premier wink Les autres options de read : -r permet de ne
pas considérer l'anti-slash comme un caractère d'échappement (ça peut
donner des choses suprenantes lorsque ce n'est pas pas ce que l'on
désire), et le « -a noms » dit que « noms » est un tableau.

Voilà qui va augmenter ton arsenal de méthodes dans les scripts bash wink

Hors ligne

#5 19-02-2016 00:31:34

enicar
Membre
Lieu : pas ici
Distrib. : sid
Noyau : Linux 6.5.3
(G)UI : openbox
Inscription : 26-08-2010

Re : [RESOLU] un tableau bash et des indices avec espaces

Spirale21 a écrit :

Alors ça marche à moitié... j'ai utilisé la deuxième méthode celle de l'IFS. ça marche mais quand tu rétablit l'IFS le nombre d'arguments dans le tableau est toujours bon mais il affiche pas correctement


for i in ${nom[@]}
do
 echo $1
done
 


En effet lorsque tu veux parcourir un tableau il faut faire « for i in "${nom[@]}"; do  » au lieu
de « for i in ${nom[@]} »…  Les " autour du tableau sont très importantes ici wink

Spirale21 a écrit :

mais t'es trop fort !!! ça m’énerverai presque


Je ne suis pas fort, j'ai juste passer du temps à apprendre à faire des scripts
bash corrects… et ça prend du temps wink D'ailleurs, tu n'es pas au bout de
tes déboires avec les scripts bash, la bonne manière de faire est souvent
surprenante wink J'ai trouvé perl, ruby et python nettement plus facile à
apprendre smile

Dernière modification par enicar (19-02-2016 00:33:43)

Hors ligne

#6 19-02-2016 11:23:18

enicar
Membre
Lieu : pas ici
Distrib. : sid
Noyau : Linux 6.5.3
(G)UI : openbox
Inscription : 26-08-2010

Re : [RESOLU] un tableau bash et des indices avec espaces

La nuit porte conseil, c'est bien connu. Et j'ai trouvé une autre
solution à base de mapfile/readarray qui n'utilise pas de
fichier temporaire (pas explicitement en tous cas). Et je trouve que
c'est la meilleure façon de faire :


mapfile -t noms < <(sort -u no.txt)
 


Le « <( ) » est l'opérateur de substitution de tâche comme décrit ici :
http://mywiki.wooledge.org/BashGuide/In … bstitution

En gros cet opérateur va créer un tube nommé dans lequel va écrire la
commande entre parenthèse (« sort -u no.txt » ici). Comme
mapfile lit les données depuis l'entrée standard, on la redirige
pour qu'elle « pointe » sur le tube nommé (le premier « < »  dans le sens
de lecture).

J'en profite pour te recommander la lecture de ce wiki :
http://mywiki.wooledge.org/BashGuide
C'est vraiment une source d'information sur comment faire des
scripts porpres avec bash. C'est souvent là que je trouve une
solution à mes problèmes en bash wink

Hors ligne

Pied de page des forums