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

script de nettoyage d'une arborescence

6 réponses
Avatar
Christophe Raverdy
Bonjour.

J'ai le besoin suivant : je dois parcourir tous les fichiers
présents dans une arborescence, vérifier si chacun de ces fichiers
contient ou non une certaine ligne et la supprimer si c'est le cas.

Quelles sont vos remarques sur le scrip que je propose ?

==========================================
#!/bin/sh
tar czvf faq.tgz faq/
REP=`ls -1R faq`
for FICHIER in $REP
do
sed -e '/^X-No-Productlink:'/d $FICHIER > $FICHIER
done
==========================================

bonus track (mais je suis prêt à chercher) : comment faire pour virer de
la liste les fichiers dont le nom se termine par ".old" ? je suppose que
je dois passer par les expressions régulières, et (éventuellement ?)
par find.

Par avance, merci pour vos éclaircissements et liens pertinents.

6 réponses

Avatar
Stephane Dupille
Bonjour.


'lu

tar czvf faq.tgz faq/
REP=`ls -1R faq`
for FICHIER in $REP


for i in $REP/**/ ;
me parait être un poil mieux que de forker le ls, si le shell le
permet. Sinon, un find :

find $REP -type f -exec sed... ';'

sed -e '/^X-No-Productlink:'/d $FICHIER > $FICHIER


Tu ne peux pas faire ça. Il y a une chance sur deux que le shell
écrase le fichier $FICHIER avant que sed ne l'ouvre. Donc sed ne verra
qu'un fichier vide. Le mieux est d'utiliser l'option -i (inplace) de
sed pour éviter ce problème.

bonus track (mais je suis prêt à chercher) : comment faire pour virer de
la liste les fichiers dont le nom se termine par ".old" ? je suppose que
je dois passer par les expressions régulières, et (éventuellement ?)
par find.


Au lieu de lancer le sed, tu fais qqchose du genre (c'est pas du
code, c'est de l'algo, j'ai la flemme de faire du vrai code) :

if (nom != '*.old)
sed
fi

Si tu utilises find, tu peux faire (pas testé) :
find $REP -type f -not -name '*.old' -exec sed... ';'

Par avance, merci pour vos éclaircissements et liens pertinents.


Ah mais de rien, HTH

Avatar
Jacques L'helgoualc'h
Le 05-02-2007, Stephane Dupille a écrit :
Bonjour.


'lu


bonjour,

tar czvf faq.tgz faq/
REP=`ls -1R faq`



Comme tar peut prendre un certain temps, le ls peut être un peu
différent ; sa sortie est polluée par des lignes vides, suivie des noms
de sous-répertoires suivis de « : ». On pourrait la purger avec un

sed '1d;/./!{N;d}'

mais ces sous-répertoires apparaissent aussi au-dessus, dans la liste de
leur parent...

for FICHIER in $REP


for i in $REP/**/ ;
me parait être un poil mieux que de forker le ls, si le shell le
permet. Sinon, un find :

find $REP -type f -exec sed... ';'
[...]


Tar fournit déjà la liste des fichiers à traiter, donc

for FICHIER in $(tar cvzf temp.tgz .tmp|grep -vE '.old$|/$')
do
sed -i -e '/^X-No-Productlink:/d' "$FICHIER"
done

pourrait suffire, du moins s'il n'y a pas de saut de ligne dans les noms
de fichiers, et autres fourberies. Sinon,

find ... -print0 | xargs -0 sed -i -e 'commande' <pas de fichier>

Par avance, merci pour vos éclaircissements et liens pertinents.


Ah mais de rien, HTH


++
--
Jacques L'helgoualc'h


Avatar
lhabert
Christophe Raverdy :

REP=`ls -1R faq`
for FICHIER in $REP


<insérer ici la rengaine sur les caractères à la con dans les noms de
fichiers, j'ai la flemme de la resortir, ça passe pratiquement tous les
jours sur ce NG, regarder du côté de find pour quelque chose de plus
robuste.>

sed -e '/^X-No-Productlink:'/d $FICHIER > $FICHIER


Là, tu vas flinguer tous tes fichiers, car le shell ouvre $FICHIER en
écriture, et le tronque, avant de lancer sed... Il faut faire quelque chose
comme

sed ... > $FICHIER.new
mv $FICHIER.new $FICHIER

(perso, je ferais ça en deux passes : création des .new, vérification que
c'est bon, puis une passe de renommage)

ou, en plus acrobatique :

(for fichier in $REP; do
exec < "$fichier"
rm "$fichier"
sed -e ... > "$fichier"
done)

(explication : tu ouvres le fichier en lecture, puis tu l'effaces, mais tu
gardes le fd 0 ouvert dessus, donc le fichier existe toujours, puis tu
recrées un fichier vide de même nom, et enfin tu lances sed, qui va donc
lire sur l'ancien fichier et écrire sur le nouveau.)

À noter : la version GNU de sed a une option « -i » pour simplifier ça.

bonus track (mais je suis prêt à chercher) : comment faire pour virer de
la liste les fichiers dont le nom se termine par ".old" ?


find . -name '*.old' -exec rm -- '{}' +

Avatar
lhabert
Stephane Dupille :

Il y a une chance sur deux que le shell écrase le fichier $FICHIER avant
que sed ne l'ouvre.


Et même une chance sur une.

Avatar
Hugues
B'jour,

Ce cher Jacques L'helgoualc'h <lhh+ a dit :

Le 05-02-2007, Stephane Dupille a écrit :

tar czvf faq.tgz faq/
REP=`ls -1R faq`



Comme tar peut prendre un certain temps, le ls peut être un peu
différent ; sa sortie est polluée par des lignes vides, suivie des noms
de sous-répertoires suivis de « : ». On pourrait la purger avec un


En plus, utiliser ls pour obtenir une liste de fichiers, c'est MAL. ls sert a
formater une liste de fichiers de facon "human-friendly", mais absolument pas
de facon "machine-friendly".

Il y a plein d'autres methodes beaucoup plus sures, en passant par les
wildcards du shell ou par find.

for FICHIER in $REP


for i in $REP/**/ ;
me parait être un poil mieux que de forker le ls, si le shell le
permet.



toutafait.

Sinon, un find :

find $REP -type f -exec sed... ';'


Tar fournit déjà la liste des fichiers à traiter, donc

for FICHIER in $(tar cvzf temp.tgz .tmp|grep -vE '.old$|/$')
do
sed -i -e '/^X-No-Productlink:/d' "$FICHIER"
done



Je propose aussi cela :

tar cvzf faq.tgz faq | grep -vE '.old$|/$' | xargs -l1 sed -i -e '/^X-No-Productlink:/d'

Sauf qu'il faut gicler les noms de dossiers dans le resultat de tar, et ce
n'est pas forcement evident, donc ca demande un peu de boulot en plus.
Toujours garder un truc a l'esprit avec unix : FAIRE SIMPLE ET FACILE. :)

Mais par contre, big problem, ca ne va pas rediriger le resultat dans un fichier
mais dans le terminal. Et la ca devient un peu plus complique, du coup.

Pourrait suffire, du moins s'il n'y a pas de saut de ligne dans les noms
de fichiers, et autres fourberies. Sinon,

find ... -print0 | xargs -0 sed -i -e 'commande' <pas de fichier>


Ou encore

find ... -exec sed -i -e "s/truc/blabla/" '{}' ';'

et pour ignorer les *.old :

find ./faq -type f -name "*.old" -prune -o -type f -exec sed ..... '{}' ';'

Mais comme il y a la redirection a faire, je ferais plutot ceci :

for i in $(find ./faq -type f -name "*.old" -prune -o -type f)
do
sed blablablablabla $i > $i.new
done

puis apres verification du resultat :

for i in **/*.new
do
mv $i ${i/.new$/}
done

et basta :)

La, c'est tout de suite mieux, non ?

--
Hugues - Debianiste avant tout - http://www.hiegel.fr/~hugues/Linux/



Avatar
Jacques L'helgoualc'h
Le 06-02-2007, Hugues a écrit :

B'jour,


'lut.

Ce cher Jacques L'helgoualc'h <lhh+ a dit :
Le 05-02-2007, Stephane Dupille a écrit :

tar czvf faq.tgz faq/
REP=`ls -1R faq`



Comme tar peut prendre un certain temps, le ls peut être un peu
différent ; sa sortie est polluée par des lignes vides, suivie des noms
de sous-répertoires suivis de « : ». On pourrait la purger avec un


En plus, utiliser ls pour obtenir une liste de fichiers, c'est MAL. ls sert a
formater une liste de fichiers de facon "human-friendly", mais absolument pas
de facon "machine-friendly".


Bon, de toutes façons c'est carrément faux : les noms de fichiers ne
sont pas préfixés par leur chemin (GNU ls).

Par contre, les options -p ou -F permettent de filtrer les
sous-répertoires, et il y a aussi --ignore='*.old" qui peut servir.

[...]
Tar fournit déjà la liste des fichiers à traiter, donc

for FICHIER in $(tar cvzf temp.tgz .tmp|grep -vE '.old$|/$')
do
sed -i -e '/^X-No-Productlink:/d' "$FICHIER"
done


Je propose aussi cela :

tar cvzf faq.tgz faq | grep -vE '.old$|/$' | xargs -l1 sed -i -e '/^X-No-Productlink:/d'


pas besoin du -l1, sed -i -e commandes traitera plusieurs fichiers à la
fois.

Sauf qu'il faut gicler les noms de dossiers dans le resultat de tar,
et ce n'est pas forcement evident, donc ca demande un peu de boulot en
plus.


mais non, c'est ce qu'a fait le « grep -v '$/' » --- tar ne répète pas
les noms de sous-répertoire (ça, j'ai vérifié (avec GNU tar (mais ça
doit être portable ?))).

Toujours garder un truc a l'esprit avec unix : FAIRE SIMPLE ET FACILE. :)


Ouaip :) --- m'enfin, ça peut être facile pas à pas, mais le résultat
final, hmmm, disons qu'il peut donner une idée de la puissance d'un
shell *nix.

Mais par contre, big problem, ca ne va pas rediriger le resultat dans un fichier
mais dans le terminal. Et la ca devient un peu plus complique, du coup.


Ah oui, j'avais négligé cet aspect verbose ; bon, insérer un tee dans le
pipe doit le faire, tee -f >(la suite du pipe...), ou utiliser les >&3
qu'aime Stéphane Chazelas.

Pourrait suffire, du moins s'il n'y a pas de saut de ligne dans les noms
de fichiers, et autres fourberies. Sinon,

find ... -print0 | xargs -0 sed -i -e 'commande' <pas de fichier>


Ou encore

find ... -exec sed -i -e "s/truc/blabla/" '{}' ';'


Là, c'est moins bien qu'avec xargs, on forke un sed par fichier --- et
il vaut mieux « simplequoter » les commandes sed, en général.

et pour ignorer les *.old :

find ./faq -type f -name "*.old" -prune -o -type f -exec sed ..... '{}' ';'

Mais comme il y a la redirection a faire, je ferais plutot ceci :

for i in $(find ./faq -type f -name "*.old" -prune -o -type f)
do
sed blablablablabla $i > $i.new
done

puis apres verification du resultat :

for i in **/*.new
do
mv $i ${i/.new$/}
done

et basta :)

La, c'est tout de suite mieux, non ?


Ben non,

- tu forkes à gogo ;

- tu explores trois fois la même arborescence ;

- tu as oublié de quoter les variables, c'est Mal©. :)

--
Jacques L'helgoualc'h