L'approche de @ meuh est inefficace car son -maxdepth 1
approche permet toujours de find
lire le contenu des répertoires au niveau 1 pour les ignorer ultérieurement autrement. Il ne fonctionnera pas non plus correctement avec certaines find
implémentations (y compris GNU find
) si certains noms de répertoire contiennent des séquences d'octets qui ne forment pas de caractères valides dans les paramètres régionaux de l'utilisateur (comme pour les noms de fichiers dans un codage de caractères différent).
find . \( -name . -o -prune \) -extra-conditions-and-actions
est la manière la plus canonique d'implémenter GNU -maxdepth 1
(ou FreeBSD -depth -2
).
En règle générale, c'est que -depth 1
vous voulez ( -mindepth 1 -maxdepth 1
) que vous ne voulez pas considérer .
(profondeur 0), et c'est encore plus simple:
find . ! -name . -prune -extra-conditions-and-actions
Car -maxdepth 2
cela devient:
find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions
Et c'est là que vous rencontrez les problèmes de caractères non valides.
Par exemple, si vous avez un répertoire appelé Stéphane
mais qui é
est encodé dans le jeu de caractères iso8859-1 (aka latin1) (0xe9 octet) comme c'était le plus courant en Europe occidentale et en Amérique jusqu'au milieu des années 2000, alors cet octet 0xe9 n'est pas un caractère valide en UTF-8. Ainsi, dans les paramètres régionaux UTF-8, le *
caractère générique (avec certaines find
implémentations) ne correspondra pas Stéphane
tel quel *
ou plusieurs caractères et 0xe9 n'est pas un caractère.
$ locale charmap
UTF-8
$ find . -maxdepth 2
.
./St?phane
./St?phane/Chazelas
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith
$ find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St?phane/Chazelas/age
./St?phane/Chazelas/gender
./St?phane/Chazelas/address
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith
Mon find
(lorsque la sortie est envoyée à un terminal) affiche cet octet 0xe9 non valide comme ?
ci-dessus. Vous pouvez voir que ce St<0xe9>phane/Chazelas
n'était pas prune
d.
Vous pouvez contourner ce problème en faisant:
LC_ALL=C find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions
Mais notez que cela affecte tous les paramètres régionaux find
et toutes les applications qu'il exécute (comme via les -exec
prédicats).
$ LC_ALL=C find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St??phane
./St??phane/Chazelas
./John
./John/Smith
Maintenant, je reçois vraiment un -maxdepth 2
mais notez comment le é du second Stéphane correctement codé en UTF-8 est affiché comme ??
les octets 0xc3 0xa9 (considérés comme deux caractères individuels non définis dans les paramètres régionaux C) du codage UTF-8 de é sont caractères non imprimables dans les paramètres régionaux C.
Et si j'avais ajouté un -name '????????'
, j'aurais eu le mauvais Stéphane (celui encodé en iso8859-1).
Pour appliquer à des chemins arbitraires au lieu de .
, vous feriez:
find some/dir/. ! -name . -prune ...
pour -mindepth 1 -maxdepth 1
ou:
find some/dir/. \( ! -path '*/./*/*' -o -prune \) ...
pour -maxdepth 2
.
Je ferais quand même:
(cd -P -- "$dir" && find . ...)
D'abord parce que cela raccourcit les chemins, ce qui le rend moins susceptible de rencontrer des problèmes de chemin trop longs ou de liste d'arguments trop longs , mais aussi de contourner le fait qu'il find
ne peut pas prendre en charge les arguments de chemin arbitraires (sauf -f
avec FreeBSD find
) car il s'étouffera valeurs $dir
similaires !
ou -print
...
La -o
combinaison avec la négation est une astuce courante pour exécuter deux ensembles indépendants de -condition
/ -action
in find
.
Si vous souhaitez exécuter une -action1
réunion de fichiers -condition1
et indépendamment une -action2
réunion de fichiers -condition2
, vous ne pouvez pas:
find . -condition1 -action1 -condition2 -action2
Comme -action2
ne serait exécuté que pour les fichiers répondant aux deux conditions.
Ni:
find . -contition1 -action1 -o -condition2 -action2
Comme -action2
ne serait pas exécuté pour les fichiers qui remplissent les deux conditions.
find . \( ! -condition1 -o -action1 \) -condition2 -action2
fonctionne comme \( ! -condition1 -o -action1 \)
résoudrait true pour chaque fichier. Cela suppose que -action1
c'est une action (comme -prune
, -exec ... {} +
) qui retourne toujours vrai . Pour des actions comme -exec ... \;
celle-ci peuvent retourner faux , vous voudrez peut-être ajouter un autre -o -something
où -something
est inoffensif mais renvoie vrai comme -true
dans GNUfind
ou -links +0
ou -name '*'
(bien que notez le problème des caractères invalides ci-dessus).
-depth -2
,-depth 1
... l'approche pourrait être considérée comme meilleure que celle de GNU-maxdepth
/-mindepth