find argument dynamic et expansion

Le
Christophe PEREZ
Bonjour,

Je butte sur un truc qui doit être tout bête.

Je fais un script bash pour faire une recherche de fichier contenant
certains caractères.
Je souhaite que le dossiers dans lequel se fait la recherche soit un
paramètre passé Í  la commande find, de même que pour le/les dossiers Í 
exclure, et c'est bien sur ce dernier point que se pose le problème.

En effet, si je ne m'abuse, pour exclure les fichiers d'un chemin, il
faut utiliser la syntaxe :
-not -path "chemin/*"

Or, quand je construis ma commande de la sorte, l'exclusion n'est pas
prise en compte. Pourtant, cette même commande fonctionne dans un shell
bash.

Il me semble que le problème se situe au niveau de l'expansion du "*"
final mais je ne parviens pas Í  trouver comment le résoudre.

Pour clarifier mes explications, une version simplifiée du script :

#!/bin/bash
DIRS="/chemin/"
EXCLUDES="/chemin/a_exclure"
EXfor DIR in $EXCLUDES; do
EX="$EX -not -path "$DIR/*""
done
LISTE=$(find $DIRS $EX -regex '.*[^a-zA-Z./_0-9-].*')
echo "$LISTE"
echo "find $DIRS $EX -regex '.*[^a-zA-Z./_0-9-].*'"

J'ai essayé pas mal de choses, en échappant *, avec, sans ou en
échappant les ". sans résultat. Et mes multiples recherchent ne m'ont
sans doute pas amené aux bonnes réponses, qui existent forcément.

Merci d'avance.
  • Partager ce contenu :
Vos réponses
Trier par : date / pertinence
Christophe PEREZ
Le #26574163
Comme si le fait de poster la question faisait systématiquement réfléchir
différemment, évident, j'ai trouvé ma réponse :
Le Wed, 26 May 2021 19:15:12 +0000, Christophe PEREZ a écrit :
EX> for DIR in $EXCLUDES; do
EX="$EX -not -path "$DIR/*""
done LISTE=$(find $DIRS $EX -regex '.*[^a-zA-Z./_0-9-].*')


en remplaçant par un tableau, et en ne quotant plus la partie "-not -path"
cela fonctionne. J'ai trop focalisé sur le * en fait.
EX=()
for DIR in $EXCLUDES; do
EX+=(-not -path "$DIR/*" )
done
find "$DIRS" "${EX[@]}" -regex '.*[^a-zA-Z./_0-9-].*'
Thomas
Le #26574166
In article Christophe PEREZ
Comme si le fait de poster la question faisait systématiquement réfléchir
différemment, évident, j'ai trouvé ma réponse :

ça m'est déjÍ  arrivé de :
- écrire un msg presque entier,
- et le fait de m'arracher les cheveux pour trouver comment expliquer
clairement mon pb aux autres, m'a permis de trouver la réponse avant de
cliquer sur envoyer ! grrr ...
il me semble que c'est un truc connu en pédagogie :
le fait de vouloir transmettre ses connaissances aux autres, et de
vouloir le faire bien, permet de les approfondir et de les parfaire :-)
--
RAPID maintainer
http://savannah.nongnu.org/projects/rapid/
Christian Weisgerber
Le #26574172
On 2021-05-26, Christophe PEREZ
#!/bin/bash
DIRS="/chemin/"
EXCLUDES="/chemin/a_exclure"
EX> for DIR in $EXCLUDES; do
EX="$EX -not -path "$DIR/*""
done
LISTE=$(find $DIRS $EX -regex '.*[^a-zA-Z./_0-9-].*')

Montrons les arguments exacts passés Í  find :
for i in $DIRS $EX -regex '.*[^a-zA-Z./_0-9-].*'; do echo "[$i]"; done
[/chemin/]
[-not]
[-path]
["/chemin/a_exclure/*"] # !!!
[-regex]
[.*[^a-zA-Z./_0-9-].*]
Aha ! Les guillemets sont préservés, donc les noms de fichiers ne
correspondent pas au motif.
Autre chose : Dans ce cas, car les guillemets résultent du remplacement
d'un paramètre, ils n'empêchent pas le développement des noms de
fichiers. Exemple :
$ touch '"foo"'
$ FOO='"*"'
$ echo $FOO
"foo"
Le problème, c'est que tu veux (1) faire la séparation des mots et
(2) empêcher le développement des noms de fichiers. Malheureusement,
« "$EX" » empêche tous les deux et « $EX » permet tous les deux.
Quoi faire ?
Une solution possible, qui est disponible dans tous les shells POSIX,
y compris bash, c'est supprimer le développement des noms de fichiers
avec « set -f ».
#!/bin/sh
DIRS="/chemin/"
EXCLUDES="/chemin/a_exclure"
EX for DIR in $EXCLUDES; do
EX="$EX -not -path $DIR/*" # <---
done
set -f # <---
find $DIRS $EX -regex '.*[^a-zA-Z./_0-9-].*'
PS :
« -not » et « -regex » ne sont pas standard.
Au place de « -not », utilise « ! ».
Ici, « -regex » n'emporte pas d'avantage. On peut faire la même chose
avec « -path » :
-path '*[!a-zA-Z./_0-9-]*'
--
Christian "naddy" Weisgerber
Thomas
Le #26574169
In article Christophe PEREZ
En effet, si je ne m'abuse, pour exclure les fichiers d'un chemin, il
faut utiliser la syntaxe :
-not -path "chemin/*"

le fait que * ne marche pas, ça doit être Í  cause du moment o͹ le shell
exécute l'expansion : il faut qu'il trouve un '*' Í  ce moment lÍ  :
peut être '\*' ?
(je ne connais pas le shell suffisamment)
mais je ne comprend pas pourquoi
"-not -path chemin1/*" "-not -path chemin2/*"
fonctionnerais, et pas
"-not -path chemin1/* -not -path chemin2/*"
par contre, pourquoi n'utilises tu pas -prune ?
qui a l'air d'être fait pour ça d'après le man, pour éviter de parcourir
des branches de l'arborescence que tu veux uniquement ignorer
(je ne peux pas te dire précisément comment on s'en sert, parce que je
ne connais pas suffisamment la grammaire des arguments de find)
--
RAPID maintainer
http://savannah.nongnu.org/projects/rapid/
Christophe PEREZ
Le #26574171
Le Wed, 26 May 2021 23:28:00 +0200, Thomas a écrit :
ça m'est déjÍ  arrivé de :
- écrire un msg presque entier,
- et le fait de m'arracher les cheveux pour trouver comment expliquer
clairement mon pb aux autres, m'a permis de trouver la réponse avant de
cliquer sur envoyer ! grrr ...

Alors je dois poster Í  peine plus tÍ´t que toi, parce que moi, c'est
toujours après avoir posté :D
il me semble que c'est un truc connu en pédagogie :
le fait de vouloir transmettre ses connaissances aux autres, et de
vouloir le faire bien, permet de les approfondir et de les parfaire

C'est sÍ»r que ça peut avoir une influence. Ça ne peut pas être du au
hasard Í  chaque fois. Pourtant, je t'assure que je tente toujours de
faire preuve de méthode et de logique, et de faire toutes les recherches
auxquelles je pense, avant de poster, puisque je sais ce qui m'arrive si
souvent.
Christophe PEREZ
Le #26574170
Le Wed, 26 May 2021 23:47:25 +0200, Thomas a écrit :
le fait que * ne marche pas, ça doit être Í  cause du moment o͹ le shell
exécute l'expansion : il faut qu'il trouve un '*' Í  ce moment lÍ  :
peut être '\*' ?
(je ne connais pas le shell suffisamment)

J'ai essayé pas mal de choses, mais de façon bien trop pifométrique.
mais je ne comprend pas pourquoi "-not -path chemin1/*" "-not -path
chemin2/*"
fonctionnerais, et pas "-not -path chemin1/* -not -path chemin2/*"

Je ne saurai te dire.
par contre, pourquoi n'utilises tu pas -prune ?

Tout simplement parce que toutes les recherches que j'ai faites pour
exclure un chemin par find m'ont orienté vers ça et que je n'ai pas plus
de compétence que toi pour mieux utiliser prune, même si je me souviens
avoir déjÍ  essayé.
qui a l'air d'être fait pour ça d'après le man, pour éviter de parcourir
des branches de l'arborescence que tu veux uniquement ignorer
(je ne peux pas te dire précisément comment on s'en sert, parce que je
ne connais pas suffisamment la grammaire des arguments de find)

Il faut quand même avouer que find, c'est quand même un peu tordu, et pas
très intuitif, c'est le moins que l'on puisse dire.
Christophe PEREZ
Le #26574215
Le Wed, 26 May 2021 21:42:15 +0000, Christian Weisgerber a écrit :
Le problème, c'est que tu veux (1) faire la séparation des mots et (2)
empêcher le développement des noms de fichiers. Malheureusement,
« "$EX" » empêche tous les deux et « $EX » permet tous les deux.

Ah voilÍ  !
Merci pour toutes ces explications, que je vais prendre le temps de bien
relire, voire tester pour bien comprendre.
Ici, « -regex » n'emporte pas d'avantage. On peut faire la même chose
avec « -path » :
-path '*[!a-zA-Z./_0-9-]*'

Exact !
Merci aussi pour ce complément de correction.
Poster une réponse
Anonyme