web-dev-qa-db-fra.com

Comment utiliser l'option '-Prune' de 'trouver' dans sh?

Je ne comprends pas très bien l'exemple donné par le man find, peut-on me donner des exemples et des explications? Puis-je combiner l'expression régulière en elle?


La question plus détaillée est la suivante:

Ecrivez un script Shell, changeall, qui a une interface comme changeall [-r|-R] "string1" "string2". Il trouvera tous les fichiers avec un suffixe de .h, .C, .cc, ou .cpp et changer toutes les occurrences de string1 à string2. -r est une option permettant de rester dans le répertoire actuel uniquement ou avec les sous-répertoires.

REMARQUE:

  1. Pour les cas non-récursifs, ls n'est PAS autorisé, nous ne pourrions utiliser que find et sed.
  2. J'ai essayé find -depth _ mais ce n'était PAS supporté. C'est pourquoi je me demandais si -Prune pourrait aider, mais n'a pas compris l'exemple de man find.

EDIT2: Je faisais un devoir, je n’ai pas posé la question avec beaucoup de détails parce que j’aimerais le finir moi-même. Puisque je l’ai déjà fait et que je le remets, je peux maintenant poser toute la question. De plus, j'ai réussi à terminer la mission sans utiliser -Prune, mais aimerait l’apprendre quand même.

204
derrdji

Ce que j'avais trouvé déroutant à propos de -Prune, C'est que c'est une action (comme -print), Pas un test (comme -name). Il modifie la liste des tâches mais renvoie toujours la valeur true .

Le schéma général d'utilisation de -Prune Est le suivant:

find [path] [conditions to Prune] -Prune -o \
            [your usual conditions] [actions to perform]

Vous voulez presque toujours que -o (OU logique) immédiatement après -Prune, Car cette première partie du test (y compris -Prune) Retournera false pour ce que vous voulez réellement (par exemple: ce que vous ne voulez pas Taillez dehors).

Voici un exemple:

find . -name .snapshot -Prune -o -name '*.foo' -print

Cela trouvera les fichiers "* .foo" qui ne se trouvent pas dans les répertoires ".snapshot". Dans cet exemple, -name .snapshot Constitue le [conditions to Prune], Et -name '*.foo' -print Est [your usual conditions] Et [actions to perform].

Notes importantes:

  1. Si vous souhaitez simplement imprimer les résultats, vous serez peut-être habitué à ne pas utiliser l'action -print. En général vous ne voulez pas lorsque vous utilisez -Prune.

    Le comportement par défaut de find consiste à "et" l'expression ( entière avec l'action -print S'il n'y a pas d'autres actions que -Prune (Ironiquement) à la fin. Cela signifie qu'écrire ceci:

    find . -name .snapshot -Prune -o -name '*.foo'              # DON'T DO THIS
    

    est équivalent à écrire ceci:

    find . \( -name .snapshot -Prune -o -name '*.foo' \) -print # DON'T DO THIS
    

    ce qui signifie que le nom du répertoire que vous élaguez sera également imprimé, ce qui n'est généralement pas ce que vous voulez. Au lieu de cela, il est préférable de spécifier explicitement l'action -print Si c'est ce que vous voulez:

    find . -name .snapshot -Prune -o -name '*.foo' -print       # DO THIS
    
  2. Si votre "condition habituelle" correspond à des fichiers qui correspondent également à votre condition d'élagage, ces fichiers ne seront pas inclus dans la sortie. Pour résoudre ce problème, ajoutez un prédicat -type d À votre condition Prune.

    Par exemple, supposons que nous voulions supprimer tous les répertoires commençant par .git (Ceci est certes quelque peu artificiel - normalement, il vous suffit de supprimer le nom exactement .git), Mais à part cela, souhaitait voir tous les fichiers, y compris les fichiers tels que .gitignore. Vous pourriez essayer ceci:

    find . -name '.git*' -Prune -o -type f -print               # DON'T DO THIS
    

    Ceci n'inclurait pas .gitignore Dans la sortie. Voici la version corrigée:

    find . -type d -name '.git*' -Prune -o -type f -print       # DO THIS
    

Astuce supplémentaire: si vous utilisez la version GNU) de find, la page texinfo pour find contient une explication plus détaillée que sa page de manuel (true) pour la plupart des GNU).

410
Laurence Gonsalves

Attention, -Prune n'empêche pas de descendre dans le répertoire any comme certains l'ont dit. Il empêche la descente dans les répertoires correspondant au test auquel il est appliqué. Peut-être que quelques exemples aideront (voir le bas pour un exemple de regex). Désolé pour être si long.

$ find . -printf "%y %p\n"    # print the file type the first time FYI
d .
f ./test
d ./dir1
d ./dir1/test
f ./dir1/test/file
f ./dir1/test/test
d ./dir1/scripts
f ./dir1/scripts/myscript.pl
f ./dir1/scripts/myscript.sh
f ./dir1/scripts/myscript.py
d ./dir2
d ./dir2/test
f ./dir2/test/file
f ./dir2/test/myscript.pl
f ./dir2/test/myscript.sh

$ find . -name test
./test
./dir1/test
./dir1/test/test
./dir2/test

$ find . -Prune
.

$ find . -name test -Prune
./test
./dir1/test
./dir2/test

$ find . -name test -Prune -o -print
.
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

$ find . -regex ".*/my.*p.$"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test/myscript.pl

$ find . -name test -Prune -regex ".*/my.*p.$"
(no results)

$ find . -name test -Prune -o -regex ".*/my.*p.$"
./test
./dir1/test
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test

$ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py

$ find . -not -regex ".*test.*"                   .
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2
26
Dennis Williamson

Normalement, notre manière de faire les choses sous Linux et notre façon de penser sont de gauche à droite.
Donc, vous écrivez ce que vous recherchez en premier:

find / -name "*.php"

Ensuite, vous appuyez probablement sur Entrée et vous réalisez que vous obtenez trop de fichiers de répertoires que vous ne souhaitez pas. Excluons/media pour éviter de rechercher vos lecteurs montés.
Vous devriez maintenant juste ajouter ce qui suit à la commande précédente:

-print -o -path '/media' -Prune

la commande finale est donc:

find / -name "*.php" -print -o -path '/media' -Prune

............... | <--- Include ---> | .................... | <- -------- Exclure ---------> |

Je pense que cette structure est beaucoup plus facile et correspond à la bonne approche

24
AmitP

Ajout au conseil donné dans d'autres réponses (je n'ai pas de représentant pour créer des réponses) ...

En combinant -Prune avec d’autres expressions, il existe une différence subtile de comportement en fonction des autres expressions utilisées.

L'exemple de @Laurence Gonsalves trouvera les fichiers "* .foo" qui ne se trouvent pas dans les répertoires ".snapshot": -

find . -name .snapshot -Prune -o -name '*.foo' -print

Cependant, ce raccourci légèrement différent listera également, peut-être par inadvertance, le .snapshot répertoire (et tous les répertoires .snapshot imbriqués): -

find . -name .snapshot -Prune -o -name '*.foo'

La raison en est (selon la page de manuel sur mon système): -

Si l'expression donnée ne contient aucune des primitives -exec, -ls, -ok ou -print, l'expression donnée est effectivement remplacée par:

(given_expression) -print

Autrement dit, le deuxième exemple équivaut à entrer le texte suivant, ce qui modifie le regroupement de termes: -

find . \( -name .snapshot -Prune -o -name '*.foo' \) -print

Cela a au moins été vu sous Solaris 5.10. Ayant utilisé diverses saveurs de * nix pendant environ 10 ans, je n’ai que récemment cherché la raison pour laquelle cela se produit.

9
crw

Prune est une option ne pas recurse à n’importe quel commutateur d’annuaire.

De la page de manuel

Si -pth n'est pas donné, c'est vrai; si le fichier est un répertoire, n'y descendez pas. Si -depth est donné, faux; aucun effet.

Fondamentalement, il ne sera pas inséré dans les sous-répertoires.

Prenez cet exemple:

Vous avez les répertoires suivants

  • / home/test2
  • / home/test2/test2

Si vous exécutez find -name test2:

Il retournera les deux répertoires

Si vous exécutez find -name test2 -Prune:

Il retournera seulement/home/test2 car il ne descendra pas dans/home/test2 pour trouver/home/test2/test2

3
AdamW

Je ne suis pas un expert en la matière (et cette page a été très utile avec http://mywiki.wooledge.org/UsingFind )

Je viens de remarquer que -path Est pour un chemin qui correspond totalement à la chaîne/chemin qui vient juste après find (. Dans ces exemples) où -name Correspond à tous les noms de base.

find . -path ./.git  -Prune -o -name file  -print

bloque le répertoire .git dans votre répertoire actuel ( en tant que résultat dans .)

find . -name .git  -Prune -o -name file  -print

bloque tous les sous-répertoires .git de manière récursive.

Notez que le ./ Est extrêmement important !! -path Doit correspondre à un chemin ancré à . ou à tout ce qui vient juste après find si vous obtenez des correspondances avec elle ( de l'autre côté du ou '-o') il n'y a probablement pas de taille! J'ignorais naïvement cela et cela m'a mis à utiliser -path quand c'est génial quand vous ne voulez pas tailler tout le sous-répertoire avec le même nom de base: D

2
sabgenton

Afficher tout, y compris dir, mais pas son contenu long et ennuyeux:

find . -print -name dir -Prune
1
devon

Si vous lisez toutes les bonnes réponses ici, je pense maintenant que les suivantes donnent les mêmes résultats:

find . -path ./dir1\*  -Prune -o -print

find . -path ./dir1  -Prune -o -print

find . -path ./dir1\*  -o -print
#look no Prune at all!

Mais le dernier prendra beaucoup plus de temps car il cherche toujours tout dans dir1. Je suppose que la vraie question est de savoir comment -or Supprimer les résultats non désirés sans les rechercher.

Donc, je suppose que Prune signifie ne pas faire de matches passés corrects, mais le marquer comme terminé ...

http://www.gnu.org/software/findutils/manual/html_mono/find.html "Cela n'est toutefois pas dû à l'effet de l'action '-Prune' (qui empêche uniquement la descente ultérieure , cela ne garantit pas que nous ignorons cet élément). Au lieu de cela, cet effet est dû à l'utilisation de "-o". Puisque le côté gauche de la condition "ou" a réussi pour ./src/emacs, il est inutile d’évaluer le côté droit ("-print") pour ce fichier particulier. "

0
sabgenton

find construit une liste de fichiers. Il applique le prédicat que vous avez fourni à chacun et renvoie ceux qui passent.

Cette idée que -Prune signifie que exclure des résultats était vraiment déroutant pour moi. Vous pouvez exclure un fichier sans Prune:

find -name 'bad_guy' -o -name 'good_guy' -print  // good_guy

Tout -Prune ne modifie pas le comportement de la recherche. Si la correspondance en cours est un répertoire, il est indiqué "hey find, le fichier que vous venez de faire correspondre, n'y descendez pas". Il supprime simplement cette arborescence (mais pas le fichier lui-même) de la liste des fichiers à rechercher.

Il devrait être nommé -dont-descend.

0
seeker_of_bacon