Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 29/01/2022, à 19:38

headstorm

Script Bash/sh split chaine de caractère

Bonjour chère communauté!

je vous sollicite aujourd’hui car j’ai besoin de vos conseils avisés.

Je cherche à faire une petit script qui me permettrait:

    de récupérer le nom d’un fichier et le stocker dans une variable,
    de découper la chaine de caractères précédemment stockée en fonction de l’espace contenu entre 2 mots
    de stocker chaque mot dans des variables différentes pour pouvoir les manipuler par la suite.

Comment je devrais procéder selon vous?

merci par avance.

Hors ligne

#2 Le 29/01/2022, à 20:16

kamaris

Re : Script Bash/sh split chaine de caractère

Tu peux faire tout ça en une seule commande interne à bash : read.
Voir help read, en particulier les options -p et -a.

Hors ligne

#3 Le 29/01/2022, à 22:38

MicP

Re : Script Bash/sh split chaine de caractère

Bonjour

Il y a aussi :

michel@debbull:~$ nomFichier="Nom Prenom Service Action.pdf" # juste pour la démonstration
michel@debbull:~$ 
michel@debbull:~$ tableauNom=( ${nomFichier%%.*} )           # Pour enlever l'extension du nom de fichier et en faire un tableau 
michel@debbull:~$ 
michel@debbull:~$ echo ${tableauNom[0]}                      # Pour afficher le premier élément du tableau
Nom
michel@debbull:~$ echo ${tableauNom[1]}                      # Pour afficher le deuxième élément du tableau
Prenom
michel@debbull:~$ echo ${tableauNom[2]}                      # Pour afficher le troisième élément du tableau
Service
michel@debbull:~$ echo ${tableauNom[3]}                      # Pour afficher le quatrième élément du tableau
Action
michel@debbull:~$ 
michel@debbull:~$ echo ${#tableauNom[@]}                     # Pour afficher le nombre d'éléments contenus dans le tableau
4
michel@debbull:~$ 

=======
Dans un script, ça pourrait donner :

#!/bin/bash

rep="/chemin/du/repertoire"      # nom du chemin du répertoire contenant les noms de fichier pdf à traiter

for f in "$rep"/*.pdf; do        # pour récupérer chaque nom de fichier
    f="${f##*/}"                 # pour enlever le chemin du fichier
    tbl=( ${f%%.*} )             # pour enlever le point et l'extension et faire un tableau
    echo "les 4 variables sont : ${tbl[0]} ${tbl[1]} ${tbl[2]} ${tbl[3]}"
    # tu feras ici ce que tu veux faire avec les variables créées pour chacun des noms de fichier
done

Dernière modification par MicP (Le 30/01/2022, à 02:47)

Hors ligne

#4 Le 30/01/2022, à 06:17

ar barzh paour

Re : Script Bash/sh split chaine de caractère

hello MicP
un petit bug ? lol lol
remarque j'ai copié tel-quel ton script bash !! nom de rep compris , évidemment /chemin/du/repertoire n'existe pas sur mon PC

jpb@U20-04-e3:~$ cat test-pdf.sh
#!/bin/bash
rep="/chemin/du/repertoire"      # nom du chemin du répertoire contenant les noms de fichier pdf à traiter
for f in "$rep"/*.pdf; do        # pour récupérer chaque nom de fichier
    f="${f##*/}"                 # pour enlever le chemin du fichier
    tbl=( ${f%%.*} )             # pour enlever le point et l'extension et faire un tableau
    echo "les 4 variables sont : ${tbl[0]} ${tbl[1]} ${tbl[2]} ${tbl[3]}"
    # tu feras ici ce que tu veux faire avec les variables créées pour chacun des noms de fichier
done
jpb@U20-04-e3:~$ 
jpb@U20-04-e3:~$ ls *.pdf
 diapo1.pdf       gparted.pdf           'Maprocuration JP.pdf'   port.pdf           pour_chanter-V0.pdf   'tajine agneau citron confit'.pdf
 essai-ours.pdf   la_queue_du_chat.pdf   port2.pdf               pour_chanter.pdf   sortie.pdf
jpb@U20-04-e3:~$
jpb@U20-04-e3:~$ bash ./test-pdf.sh
les 4 variables sont : 10_40.txt 2021-12-12:10-16-05-1-liste-2021-12-11-V2.txt 2021-12-12:10-16-05-2-liste-2021-12-11-V2.txt 70.txt
jpb@U20-04-e3

pour info

jpb@U20-04-e3:~$ ls [127]*
10_40.txt
2021-12-12:10-16-05-1-liste-2021-12-11-V2.txt
2021-12-12:10-16-05-2-liste-2021-12-11-V2.txt
70.txt
jpb@U20-04-e3:~$ 




bien sur si je mets rep=/home/$USER
ça fonctionne bien

jpb@U20-04-e3:~$ bash ./test-pdf.sh
les 4 variables sont : diapo1   
les 4 variables sont : essai-ours   
les 4 variables sont : gparted   
les 4 variables sont : la_queue_du_chat   
les 4 variables sont : Maprocuration JP  
les 4 variables sont : port2   
les 4 variables sont : port   
les 4 variables sont : pour_chanter   
les 4 variables sont : pour_chanter-V0   
les 4 variables sont : sortie   
les 4 variables sont : tajine agneau citron confit   
jpb@U20-04-e3:~$ 

Dernière modification par ar barzh paour (Le 30/01/2022, à 06:30)


PC          : B760M DS3H DDR4,  12th Gen Intel(R) Core(TM) i3-12100, RAM DDR4 8GiB -2400 Ubuntu 20.04, 22.04, 24.04 (en test )
Portable1 : ThinkPad P50 I7-6820HQ, 16G0 Ram Ubuntu 22.04 Ubuntu 24.04 , W10-PRO( en voyage )
Portable2 : T5750  @ 2.00GHz RAM 1GiB DDR2 667 Mhz Ubuntu 20.04 ( batterie HS )
stourm a ran war bep tachenn (Angela Duval) ( Je combats sur tous les fronts )

Hors ligne

#5 Le 30/01/2022, à 06:42

Watael

Re : Script Bash/sh split chaine de caractère

si il n'y a pas de correspondance avec le motif indiqué, alors le motif lui-même est traité.
tu enlèves le chemin, et tu enlèves l'extension, il ne reste que l'astérisque auquel est substitué tous les fichiers et répertoires du répertoire courant.

pour éviter ça, en bash, il y a nullglob à passer à shopt.
autrement, il faudrait tester que chaque élément retourné par la boucle existe (test -e "$f").


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#6 Le 30/01/2022, à 06:55

ar barzh paour

Re : Script Bash/sh split chaine de caractère

tester existence de $rep suffirait-il ?


PC          : B760M DS3H DDR4,  12th Gen Intel(R) Core(TM) i3-12100, RAM DDR4 8GiB -2400 Ubuntu 20.04, 22.04, 24.04 (en test )
Portable1 : ThinkPad P50 I7-6820HQ, 16G0 Ram Ubuntu 22.04 Ubuntu 24.04 , W10-PRO( en voyage )
Portable2 : T5750  @ 2.00GHz RAM 1GiB DDR2 667 Mhz Ubuntu 20.04 ( batterie HS )
stourm a ran war bep tachenn (Angela Duval) ( Je combats sur tous les fronts )

Hors ligne

#7 Le 30/01/2022, à 07:02

Watael

Re : Script Bash/sh split chaine de caractère

non. il faut tester que ce que retourne la boucle existe, parce que même si le répertoire existe, il n'est pas dit que le motif correspondra à un fichier ou un répertoire.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#8 Le 30/01/2022, à 07:08

ar barzh paour

Re : Script Bash/sh split chaine de caractère

alors comme ça ?

for f in "$rep"/*.pdf; do        # pour récupérer chaque nom de fichier
    test -e "$f"  || continue
    f= ....
    ....
done

PC          : B760M DS3H DDR4,  12th Gen Intel(R) Core(TM) i3-12100, RAM DDR4 8GiB -2400 Ubuntu 20.04, 22.04, 24.04 (en test )
Portable1 : ThinkPad P50 I7-6820HQ, 16G0 Ram Ubuntu 22.04 Ubuntu 24.04 , W10-PRO( en voyage )
Portable2 : T5750  @ 2.00GHz RAM 1GiB DDR2 667 Mhz Ubuntu 20.04 ( batterie HS )
stourm a ran war bep tachenn (Angela Duval) ( Je combats sur tous les fronts )

Hors ligne

#9 Le 30/01/2022, à 07:22

Watael

Re : Script Bash/sh split chaine de caractère

oui, c'est bien comme ça.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#10 Le 30/01/2022, à 13:27

MicP

Re : Script Bash/sh split chaine de caractère

Bonjour

Du coup, histoire d'éviter le cas d'un nom de répertoire qui aurait un nom d'extension .pdf
autant vérifier en plus qu'il s'agit bien d'un nom de fichier, et pas d'un nom de répertoire  :

for f in "$rep"/*.pdf; do        # pour récupérer chaque nom de fichier
    test -f "$f"  || continue
    f= ....
    ....
done

Hors ligne

#11 Le 30/01/2022, à 14:02

headstorm

Re : Script Bash/sh split chaine de caractère

Bonjour,

Merci @MIcP, @Watael et @ar barzh paour pour votre aide.

j'avance dans mon script, mais je rencontre à présent un blocage (erreur de sythaxe apparemment) au niveau de ma boucle qui sert à parcourir le tableau (du numéro 3 au numéro définit par la variable $fin en incrémentant de 1).

le but est de concaténer chaque résultat dans une variable unique ensuite, car a partir de l'enregistrement numéro 3 [2] on retrouve nom et prénom, ces derniers pouvant contenir plusieurs mots (exemple DA SILVA ou encore Pierre Jean...)

N.B: le nom de mon fichier est à présent de ce type : "Societe Action Nom Prenom.pdf"
 

#
 fin=${#tbl[@]}               # compte le nombre d'enregistrement dans le tableau

<------Erreur à partir de cette instruction------>
        for i in {2..$fin..1}; do 
        name =$name ${tbl[$i]}   #ajoute l'enregistrement suivant à la variable existante
        done
        echo $name

Dernière modification par headstorm (Le 30/01/2022, à 14:07)

Hors ligne

#12 Le 30/01/2022, à 14:26

Watael

Re : Script Bash/sh split chaine de caractère

le Développement des paramètres intervient après celui des accolades.

for ((i=2;i<=fin;i+=1))

ps: le pas par défaut entre accolade est de 1; il n'est pas nécessaire de le préciser.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#13 Le 30/01/2022, à 15:16

headstorm

Re : Script Bash/sh split chaine de caractère

la syntaxe est proche d'un langage web type php au final, la doc ne mentionnait pas cette syntaxe dans le bash, quoi qu'il en soit cela fonctionne.

j'ai modifié la suite de mon instruction également car elle contenait une erreur, je partage mon script si ça peut servir a quelqu’un.

#!/bin/bash

rep="/chemin/vers/rep/"      # nom du chemin du répertoire contenant les noms de fichier pdf à traiter

for f in "$rep"/*.pdf; do        # boucle nom de fichier
    test -f "$f"  || continue    # test si fichier existe
    f="${f##*/}"                 # enleve le chemin du fichier
    f="${f%%.*}"                 # enleve l'extension
    tbl=( ${f//_/\ } )           # remplce "_" par des espaces et mets dans un tableau
    echo "les 4 variables sont : 1: ${tbl[0]} 2: ${tbl[1]} 3: ${tbl[2]} "   # affiche les variable
    fin=${#tbl[@]}               # compte le nombre d'enregistrement dans le tableau
    name=""                      # initialisation variable name

        for ((i=2;i<=$fin;i+=1)) #boucle sur enregistrements dans le tableau à partir du 2ème résultat jusqu'à la fin en incrémentant de 1
        do
        name+=" ${tbl[$i]}"   #ajoute l'enregistrement à la variable existante
        done

        echo $name   #Affiche les enregistrements concaténés
done

Merci en tout cas de votre précieuse aide et du temps que vous avez consacré à mon script. smile

Hors ligne

#14 Le 30/01/2022, à 15:32

Watael

Re : Script Bash/sh split chaine de caractère

la deuxième boucle n'est pas utile, et pourrait être problématique, puisque finalement tu ne sais pas précisément le nombre d'élément du tableau :

name=$(IFS=''; echo "${tbl[*]}")

Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#15 Le 30/01/2022, à 15:48

headstorm

Re : Script Bash/sh split chaine de caractère

Watael a écrit :

la deuxième boucle n'est pas utile, et pourrait être problématique, puisque finalement tu ne sais pas précisément le nombre d'élément du tableau :

name=$(IFS=''; echo "${tbl[*]}")

la deuxième boucle me sert à sélectionner les enregistrements de 2 à la fin du tableau car dans la seconde partie du traitement je n'ai besoin que de ceux-ci.

la taille précise est connue grâce à l'instruction:

fin=${#tbl[@]}

il me faut d'ailleurs corriger ma boucle pour qu'elle soit inférieure à fin puisque un tableau commence à 0

 for ((i=2;i<$fin;i+=1))

Mon raisonnement est bon?

Hors ligne

#16 Le 30/01/2022, à 16:09

MicP

Re : Script Bash/sh split chaine de caractère

Bonjour

#!/bin/bash

rep="/chemin/vers/repertoire"  # nom du chemin du répertoire contenant les noms de fichier pdf à traiter

for f in "$rep"/*.pdf; do      # boucle chacun des noms de fichier trouvés dans le répertoire
    test -f "$f"  || continue      # test si c'est bien un nom de fichier ordinaire existant (et pas un nom de répertoire ou autre fichier de type lien etc.)
    f="${f##*/}"                   # enlève le chemin du fichier
    f="${f%%.*}"                   # enlève l'extension
    tbl=( ${f//_/ } )              # remplace chacun des caractères "_" par un caractère espace et en fait un tableau de mots
    name="${tbl[@]:1}"             # du deuxième au dernier élément du tableau
    echo "$name"                   # affichage
done                           # fin boucle

Voir : https://wiki.bash-hackers.org/syntax/arrays

Dernière modification par MicP (Le 30/01/2022, à 17:01)

Hors ligne

#17 Le 30/01/2022, à 16:22

headstorm

Re : Script Bash/sh split chaine de caractère

MicP a écrit :

Bonjour

#!/bin/bash

rep="/chemin/vers/rep/"      # nom du chemin du répertoire contenant les noms de fichier pdf à traiter

for f in "$rep"/*.pdf; do    # boucle nom de fichier
    test -f "$f"  || continue    # test si c'est bien un nom de fichier existant (et pas un nom de répertoire)
    f="${f##*/}"                 # enlève le chemin du fichier
    f="${f%%.*}"                 # enlève l'extension
    tbl=( ${f//_/\ } )           # remplace "_" par des espaces et mets dans un tableau
    name="${tbl[@]:1}"           # du deuxième au dernier élément du tableau
    echo "$name"                 # affichage
done

Génial !! big_smile big_smile

Quel talent!

merci

Hors ligne

#18 Le 30/01/2022, à 17:56

Sciensous

Re : Script Bash/sh split chaine de caractère

f="${f##*/}"                 # enlève le chemin du fichier
f="${f%%.*}"                 # enlève l'extension

peut être remplacé par

f="$(basename "$f" .pdf)"

(réflexe de celui qui se borne à utiliser du sh et non du bash wink )
cool

Dernière modification par Sciensous (Le 30/01/2022, à 17:56)


antiX 19 et 21 et Ubuntu 20.04 et 22.04
( sous LXDE et gnome-shell )

Hors ligne

#19 Le 30/01/2022, à 20:22

MicP

Re : Script Bash/sh split chaine de caractère

Vu le titre de ce fil de discussion,
ça pourrait peut-être intéresser headstorm et les lecteurs de ce fil de discussion
d'avoir un script équivalent mais utilisant sh au lieu de bash (voire même un script posix).

Hors ligne

#20 Le 30/01/2022, à 21:02

headstorm

Re : Script Bash/sh split chaine de caractère

MicP a écrit :

Vu le titre de ce fil de discussion,
ça pourrait peut-être intéresser headstorm et les lecteurs de ce fil de discussion
d'avoir un script équivalent mais utilisant sh au lieu de bash (voire même un script posix).

Effectivement, ça serait très intéressant d'avoir une traduction de ce script en sh.
Outre le fait de nourrir mes connaissances personnelles, ça permettrait de le rendre compatible avec différents systèmes.

Hors ligne

#21 Le 31/01/2022, à 00:39

MicP

Re : Script Bash/sh split chaine de caractère

Bonjour

J'ai fait ça, mais il y a peut-être mieux à faire.

#!/bin/sh

rep="/chemin/vers/repertoire"

for f in "$rep"/*.pdf; do
    test -f "$f" || continue
    printf '%s\n' "$f" | sed 's#.*/\(.*\)\.pdf#\1#;s/_/ /g' | \
    while read -r premierMot suite; do
        name="$(printf '%s' "$suite")"
        printf '%s\n' "$name" 
    done
done

J'ai créé la variable name avec le retour de la commande printf pour l'afficher ensuite,
mais c'est seulement au cas où tu en aies besoin pour en faire quelque chose après,

parce que sinon, on peut très bien s'en passer :

#!/bin/sh

rep="/chemin/vers/repertoire"

for f in "$rep"/*.pdf; do
    test -f "$f" || continue
    printf '%s\n' "$f" | sed 's#.*/\(.*\)\.pdf#\1#;s/_/ /g' | \
    while read -r premierMot suite; do
        printf '%s\n' "$suite"
    done
done

=======
Attention, il y a un petit piège dans ces deux scripts : c'est un caractère de fin de ligne qui a été "échappé"
ce qui fait que ces deux lignes :

printf '%s\n' "$f" | sed 's#.*/\(.*\)\.pdf#\1#;s/_/ /g' | \
while read -r premierMot suite; do

sont en fait une seule ligne de commandes que j'avais trouvée trop longue :

printf '%s\n' "$f" | sed 's#.*/\(.*\)\.pdf#\1#;s/_/ /g' | while read -r premierMot suite; do

Dernière modification par MicP (Le 31/01/2022, à 06:32)

Hors ligne

#22 Le 31/01/2022, à 09:08

Watael

Re : Script Bash/sh split chaine de caractère

je trouve ça plus compréhensible de cette manière :

printf '%s\n' "$f" | sed 's#.*/\(.*\)\.pdf#\1#;s/_/ /g' \
    | while read -r premierMot suite; do

ma suggestion :

echo "$f" | sed 's#.*/\(.*\)\.pdf#\1#;s/_/ /g' | { read -r mot suite; echo "$suite";}

printf n'est pas indispensable, ici. et la boucle non plus.

Dernière modification par Watael (Le 31/01/2022, à 09:15)


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#23 Le 31/01/2022, à 10:06

MicP

Re : Script Bash/sh split chaine de caractère

Merci beaucoup pour tes conseils. smile

Hors ligne

#24 Le 31/01/2022, à 10:25

Watael

Re : Script Bash/sh split chaine de caractère

il y a quand même quelques Remplacements de paramètres possibles en POSIX.
je viens de tester sur dash :

$ f=$(echo "$f" | sed 's#.*/\(.*\)\.pdf#\1#;s/_/ /g' )
$ echo "${f#* }"

Dernière modification par Watael (Le 31/01/2022, à 10:25)


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#25 Le 31/01/2022, à 12:05

MicP

Re : Script Bash/sh split chaine de caractère

Oui, ça fonctionne très bien, et c'est beaucoup plus simple
ce qui donnerait :

#!/bin/sh

rep="/chemin/vers/repertoire"

for f in "$rep"/*.pdf; do
    test -f "$f" || continue
    f=$(echo "$f" | sed 's#.*/\(.*\)\.pdf#\1#;s/_/ /g')
    echo "${f#* }"
done

Dernière modification par MicP (Le 31/01/2022, à 12:07)

Hors ligne