Je souhaite supprimer récursivement tous les fichiers non accessibles depuis un certain temps dans le dossier a
, à l'exception de tous les fichiers du sous-dossier b
.
find a \( -name b -prune \) -o -type f -delete
Cependant, je reçois un message d'erreur:
find: l'action -delete active automatiquement -depth, mais -prune ne fait rien lorsque -depth est en vigueur. Si vous voulez continuer, utilisez simplement explicitement l'option -depth.
L'ajout -depth
entraîne l' b
inclusion de tous les fichiers , ce qui ne doit pas se produire.
Quelqu'un connaît un moyen sûr de faire fonctionner cela?
a
saufa/b
?cd a && ls -d !(b/*)
fonctionnera pas ? (Pour le faire,rm -r
plutôt quels -d
.)a
(sauf les fichiers sousa/b
).-r
rm. Il semble que ce que vous demandez est assez facilement répondu en utilisant le globbing étendu de bash, et ensuite ce que vous faites avec le résultat du globbing dépend de vous.Réponses:
TL; DR: la meilleure façon est d'utiliser à la
-exec rm
place de-delete
.Explication:
Pourquoi find se plaint-il lorsque vous essayez d'utiliser
-delete
avec-prune
?Réponse courte: car
-delete
implique-depth
et-depth
rend-prune
inefficace.Avant d'arriver à la réponse longue, observons d'abord le comportement de la recherche avec et sans
-depth
:Il n'y a aucune garantie sur la commande dans un seul répertoire. Mais il y a une garantie qu'un répertoire est traité avant son contenu. Notez
foo/
avant toutfoo/*
etfoo/bar
avant toutfoo/bar/*
.Cela peut être inversé avec
-depth
.Notez que maintenant tous
foo/*
apparaissent avantfoo/
. Même chose avecfoo/bar
.Réponse plus longue:
-prune
empêche la recherche de descendre dans un répertoire. En d'autres termes,-prune
saute le contenu du répertoire. Dans votre cas,-name b -prune
empêche la recherche de descendre dans n'importe quel répertoire portant le nomb
.-depth
fait rechercher pour traiter le contenu d'un répertoire avant le répertoire lui-même. Cela signifie qu'au moment où find parvient à traiter l'entrée de répertoire,b
son contenu a déjà été traité. Ainsi-prune
est inefficace avec-depth
en vigueur.-delete
implique-depth
qu'il peut d'abord supprimer les fichiers, puis le répertoire vide.-delete
refuse de supprimer les répertoires non vides. Je suppose qu'il serait possible d'ajouter une option pour forcer-delete
à supprimer les répertoires non vides et / ou empêcher-delete
d'impliquer-depth
. Mais c'est une autre histoire.Il existe une autre façon de réaliser ce que vous voulez:
Cela peut ou non être plus facile à retenir.
Cette commande descend toujours dans le répertoire
b
et traite chaque fichier qu'il contient uniquement pour-not
les rejeter. Cela peut être un problème de performances si le répertoireb
est énorme.-path
fonctionne différemment de-name
.-name
ne correspond qu'au nom (du fichier ou du répertoire) tandis qu'il-path
correspond au chemin entier. Par exemple, observez le chemin/home/lesmana/foo/bar
.-name -bar
correspondra car le nom estbar
.-path "*/foo*"
correspondra car la chaîne se/foo
trouve dans le chemin.-path
a quelques subtilités que vous devez comprendre avant de l'utiliser. Lisez la page de manuel defind
pour plus de détails.Attention, ce n'est pas infaillible à 100%. Il y a des chances de "faux positifs". La façon dont la commande est écrite ci-dessus ignorera tout fichier contenant un répertoire parent dont le nom commence par
b
(positif). Mais il ignorera également tout fichier dont le nom commence par,b
quelle que soit sa position dans l'arbre (faux positif). Cela peut être corrigé en écrivant une meilleure expression que"*/b*"
. Cela reste un exercice pour le lecteur.Je suppose que vous avez utilisé
a
etb
comme espaces réservés et les vrais noms ressemblent plus àallosaurus
etbrachiosaurus
. Si vous mettezbrachiosaurus
en place,b
la quantité de faux positifs sera considérablement réduite.Au moins, les faux positifs ne seront pas supprimés, ce ne sera donc pas aussi tragique. De plus, vous pouvez vérifier les faux positifs en exécutant d'abord la commande sans
-delete
(mais n'oubliez pas de placer l'implicite-depth
) et examinez la sortie.la source
-not -path
était juste la chose! Merci pour une explication généreuse!-not -path
fonctionne tout-prune
ne serait pas utile. Pourquoi peut-not -path
coexister avec-depth
?Utilisez simplement
rm
au lieu de-delete
:la source
rm
fonctionne etdelete
ne fonctionne pas?rm
n'a pas ce problème. Mais, malgré tout, l'élaboration serait une bonne chose.-delete
implique-depth
, qui ne peut évidemment pas travailler avec-prune
.-path
fonctionne, mais ne s'arrête pasfind
de descendre dans des répertoires qu'il n'a pas besoin d'explorer.Les réponses et explications ci-dessus ont été très utiles.
J'utilise les solutions de contournement de "-exec rm {} +" ou "-not -path ... -delete", mais celles-ci peuvent être beaucoup plus lentes que "find ... -delete". J'ai vu "find ... -delete "s'exécute 5 fois plus vite que" -exec rm {} + "sur les répertoires profonds d'un système de fichiers NFS.
La solution '-not path "a la surcharge évidente de regarder tous les fichiers dans les répertoires exclus et ci-dessous.
Le "find .. -exec rm {} +" appelle rm qui effectue les appels système:
Le "find -delete" fait des appels système:
Ainsi, la commande "-exec rm {} +" rm effectue le chemin complet de la recherche d'inode deux fois par fichier, mais "find -delete" effectue une statistique et dissocie le nom de fichier dans le répertoire en cours. C'est une grande victoire lorsque vous supprimez un grand nombre de fichiers dans un répertoire.
(mode pleurnicher activé (désolé))
Il semble que la conception de l'interaction entre -depth, -delete et -prune élimine inutilement la manière la plus efficace de faire l'action courante "supprimer les fichiers sauf ceux dans les répertoires -prune"
La combinaison de "-type f -delete" devrait pouvoir s'exécuter sans -depth car elle n'essaye pas de supprimer des répertoires. Alternativement, si "find" avait une action "-deletefile" qui dit de ne pas supprimer les répertoires, -depth n'aurait pas besoin d'être impliqué.
Les appels xargs ou find -exec à la commande rm pourraient être accélérés si rm avait une option pour trier les noms de fichiers, ouvrir les répertoires et ne pas lier (dir_fd, nom de fichier) au lieu de dissocier les chemins complets. Il fait déjà le lien (dir_fd, nom de fichier) lors de la récursivité dans les répertoires avec l'option -r.
(mode pleurnicher désactivé)
la source