Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[bash] bonne façon de faire une boucle sur un ensemble de fichiers contenu dans un dossier

35 réponses
Avatar
Francois Lafont
Bonjour à tous,

Assez régulièrement, je suis amené à me faire des petits scripts bash
qui font une boucle sur une liste de fichiers contenus dans un dossier
(et dans ses sous-dossiers etc). La liste de fichiers, qui peut être
assez grande, est obtenue à l'aide de la commande find. Le but est de
faire un même petit traitement sur chacun des fichiers de cette liste
via une boucle (le traitement importe peu ici, ça peut être un
"renommage", un grep etc). La structure de mes petits scripts
ressemblent à ça du coup (c'est un exemple) :

#-------------------------------------
for fichier in $(find /le/dossier/ -type f -iname '*.tex')
do
echo Traitement de $fichier
# etc.
done
#-------------------------------------

Est-ce la bonne façon de procéder ? J'ai des doutes :


1) En effet, finalement le script revient à ça :

#-------------------------------------
for fichier in /le/dossier/f1.tex /le/dossier/f2.tex /le/dossier/f3.tex
do
echo Traitement de $fichier
# etc.
done
#-------------------------------------

Du coup, si la liste est très grande, ça me semble un peu maladroit
comme script et peut-être pas très performant. (Aucune certitude bien
sûr, c'est juste une intuition.)

2) Une autre chose qui me fait penser que ce n'est peut-être pas la
bonne façon de procéder, c'est le problème avec les noms de fichiers qui
contiennent un espace. Si find détecte un fichier qui s'appelle par
exemple "/le/dossier/sous dossier/toto.tex" alors, durant la boucle,
$fichier sera égal à la chaîne "/le/dossier/sous" puis à
"dossier/toto.tex" mais jamais à "/le/dossier/sous dossier/toto.tex".

Bref, quelle est la bonne façon de faire ce genre de boucle ?
Merci d'avance pour votre aide.


--
François Lafont

10 réponses

1 2 3 4
Avatar
Doug713705
Le 22-05-2011, Francois Lafont nous expliquait dans
fr.comp.os.linux.configuration :

Bonjour à tous,



Bonjour,

#-------------------------------------
for fichier in $(find /le/dossier/ -type f -iname '*.tex')
do
echo Traitement de $fichier
# etc.
done
#-------------------------------------

Est-ce la bonne façon de procéder ? J'ai des doutes :



Je ne suis pas spécialiste mais je pense que tu peux jetter un oeil à
l'option -exec de find.

D'autres options de manipulation de fichier existent également
(-delete par ex).

man find
--
Doug - Linux user #307925 - Slackware64 roulaize ;-)
http://www.dougwise.org
http://usenet-fr.dougwise.org
http://news.dougwise.org
Avatar
Aéris
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 22/05/2011 18:27, Francois Lafont a écrit :
for fichier in $(find /le/dossier/ -type f -iname '*.tex')
do
echo Traitement de $fichier
# etc.
done



find /le/dossier/ -type f -iname '*.tex' | while read FILE; do
echo "${FILE}"
done

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN2Ts0AAoJEK8zQvxDY4P938sIAMCNjiya/RT0hJHza5O8r0aN
K3X1iutv+bCYQVm06DeU9toIhIxAh72OAQIxzzmFPycNVC+bUe3QMsCltClcRkhj
PnnswG9m1TfB6AYyUfMt3KkEspzHeDnC6OvYNGRegWe1uO30mePApI9+R7tpYpmz
3u7hIOi51CqmTve8P7xuh67SQYKqwPKkXWYOGscLI7kpaWY5720O4LVH90uCsR3x
7usbUA+C+vENxWTMz1NNmp67MwZoUSWXloYBDAABkJ6QPs38KUoj63KvCym0eRBM
NWE8UeBIQy/GpaGPmlVwhpOdWyc2wwpfCd1UkqOb5LEf67bjJLBmgQmZbk3dqxM =w5K9
-----END PGP SIGNATURE-----
Avatar
Francois Lafont
Le 22/05/2011 18:34, Doug713705 a écrit :

Je ne suis pas spécialiste mais je pense que tu peux jetter un oeil à
l'option -exec de find.



Oui, je connais l'option -exec mais le souci c'est que même si le
traitement sur chaque fichier est assez basique en général, il m'est
souvent difficile de le faire tenir sur une seule ligne. Du coup,
j'avais pensé à faire un truc dans ce genre :

function f(){
echo Traitement de $1
# etc.
}

find /le/dossier/ -type f -exec f {} ;

Mais dans l'option -exec, la fonction f semble totalement inconnue et le
code ne fonctionne pas.


--
François Lafont
Avatar
Francois Lafont
Le 22/05/2011 18:35, Aéris a écrit :

find /le/dossier/ -type f -iname '*.tex' | while read FILE; do
echo "${FILE}"
done



Merci bien Aéris, ça m'a l'air parfait. J'aimerais simplement comprendre
la différence entre ${FILE} et $FILE, je ne vois pas trop.


--
François Lafont
Avatar
xavier
Francois Lafont wrote:

find /le/dossier/ -type f -exec f {} ;

Mais dans l'option -exec, la fonction f semble totalement inconnue et le
code ne fonctionne pas.



Faut exporter la fonction, et lancer un shell dans exec :

export func
find /dossier-type f -exec sh -c 'func $1' _ {} ;

--
XAv
In your pomp and all your glory you're a poorer man than me,
as you lick the boots of death born out of fear.
(Jethro Tull)
Avatar
Nicolas George
Francois Lafont , dans le message
<4dd9395e$0$18114$, a écrit :
Assez régulièrement, je suis amené à me faire des petits scripts bash
qui font une boucle sur une liste de fichiers contenus dans un dossier
(et dans ses sous-dossiers etc). La liste de fichiers, qui peut être
assez grande, est obtenue à l'aide de la commande find.



Jette bash en faveur de zsh :

setopt extendedglob
for f in **/*.(#i)tex; {
... frobincate $f
}
Avatar
Aéris
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 22/05/2011 18:55, Francois Lafont a écrit :
Merci bien Aéris, ça m'a l'air parfait. J'aimerais simplement comprendre
la différence entre ${FILE} et $FILE, je ne vois pas trop.



Y'en a pas vraiment.
{} te permet juste de faire des trucs plus complexes, du style
BIDULE=truc
echo "${BIDULE}muche"
Sans les accolades, ça serait impossible.

Et j'ai pris l'habitude de les mettre partout du coup =)

- --
Aeris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN2UNiAAoJEK8zQvxDY4P9fhoH/ihb0ZWiFqb+8nUtVP67T+l5
Ph9eMCQ9UhqxApvQuVnuKoWWzdBH/QA/C962MRCTvsic4PCyzy5Hz3OxggYED+VG
K3LskAvdM6CR5kz79dkQMxEpGqkhJrLwUgViUcRvrlsGiVzqMtfKqKlfD36Ip34h
aeY2w00gM9HO7rEvyX1feL3W/5vR8Fe4+AF3KzQ41PgX/Lay4THhwYAbsiAHwHFh
XhTjskjhhJFdJa8JxK5+oCg7nw836pXfjqJrT8FqKTKTr9BonKEY4vyKFA/sB0nL
vwandErpWH55Ycnp78uXD/mPJS6BM5rnUtDIRzktAs50JQmMNzoLF9fUb7NnO0o =zLmP
-----END PGP SIGNATURE-----
Avatar
Nicolas George
Xavier, dans le message <1k1onot.3j3u907xvcw0N%, a
écrit :
Faut exporter la fonction, et lancer un shell dans exec :

export func
find /dossier-type f -exec sh -c 'func $1' _ {} ;



N'importe quoi.
Avatar
Nicolas George
Aéris , dans le message <4dd9436b$0$13039$, a
écrit :
BIDULE=truc
echo "${BIDULE}muche"
Sans les accolades, ça serait impossible.



echo "$BIDULE""muche"
Avatar
Francois Lafont
Le 22/05/2011 19:07, Xavier a écrit :

find /le/dossier/ -type f -exec f {} ;

Mais dans l'option -exec, la fonction f semble totalement inconnue et le
code ne fonctionne pas.



Faut exporter la fonction, et lancer un shell dans exec :



Ok, mais j'imagine pour le coup que les performances s'en trouvent
amoindries.

export func
find /dossier-type f -exec sh -c 'func $1' _ {} ;



Je crois qu'Aéris a parfaitement résolu mon problème, ceci étant, par
curiosité, j'ai essayé de faire fonctionner cette idée et je n'y suis
pas arrivé. J'ai fait ça :

function f(){
echo Traitement de $1
}
export f
find /le/dossier -type f -exec sh -c 'f $1' _ {} ;

Je ne comprends pas trop le «-c 'f $1'» et le underscore qui vient juste
après. J'ai bien tenté un "man sh", mais je tombe sur la page du shell
dash ?



Nicolas George a écrit :

Jette bash en faveur de zsh :

setopt extendedglob
for f in **/*.(#i)tex; {
... frobincate $f
}



Ah, j'ai peur de ne pas avoir le temps. Mais peut-être un jour... Ce
n'est pas la première qu'on me parle en bien de zsh.


Aéris a écrit :

Y'en a pas vraiment.
{} te permet juste de faire des trucs plus complexes, du style
BIDULE=truc
echo "${BIDULE}muche"
Sans les accolades, ça serait impossible.

Et j'ai pris l'habitude de les mettre partout du coup =)



Ok, je vois. Perso, j'utilise les doubles quote :

BIDULE=truc
echo "$BIDULE"muche

En tout cas, merci bien Aéris pour ta solution.


--
François Lafont
1 2 3 4