#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 ?
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.
En 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.
En 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.
En 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.
En 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.
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.
En ligne
#15 Le 30/01/2022, à 15:48
- headstorm
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[*]}")
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
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 !!
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 )
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
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.
En ligne
#23 Le 31/01/2022, à 10:06
- MicP
Re : Script Bash/sh split chaine de caractère
Merci beaucoup pour tes conseils.
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.
En 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