linux - prune - unix command find exclude directory




Comment exclure un répertoire dans find. commander (20)

Aucune des réponses précédentes n'est bonne sur Ubuntu. Essaye ça:

find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"

J'ai trouvé ça here

J'essaie d'exécuter une commande find pour tous les fichiers JavaScript, mais comment exclure un répertoire spécifique?

Voici le code de recherche que nous utilisons.

for file in $(find . -name '*.js'); do java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file; done

C'est le format que j'ai utilisé pour exclure certains chemins:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

J'ai utilisé ceci pour trouver tous les fichiers qui ne sont pas dans les chemins ". *":

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

Cela fonctionne car find TESTS les fichiers pour le modèle " * foo * ":

find ! -path "dir1" ! -path "dir2" -name "*foo*"

mais cela ne fonctionne PAS si vous n'utilisez pas de pattern ( find ne TEST pas le fichier). Donc, find ne fait pas usage de ses anciens booléens « vrais » et « faux » évalués. Exemple de cas d'utilisation ne fonctionnant pas avec la notation ci-dessus:

find ! -path "dir1" ! -path "dir2" -type f

Il n'y a pas de test de find ! Donc, si vous avez besoin de trouver des fichiers sans correspondance, utilisez -prune. En outre, l'utilisation de prune find est toujours plus rapide alors qu'elle saute vraiment ces répertoires au lieu de les faire correspondre ou mieux de ne pas les faire correspondre. Alors, dans ce cas, utilisez quelque chose comme:

find dir -not \( -path "dir1" -prune \) -not \( -path "dir2" -prune \) -type f

ou:

find dir -not \( -path "dir1" -o -path "dir2" -prune \) -type f

Cordialement


Cela me convient sur un Mac:

find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune

Il exclura le répertoire du vendor et de l' app/cache pour le nom de la recherche qui a un suffixe avec php .


Il y a clairement une certaine confusion ici quant à ce que devrait être la syntaxe préférée pour sauter un répertoire.

Avis GNU

To ignore a directory and the files under it, use -prune

À partir de la page de manuel de recherche GNU

Raisonnement

-prune arrête de find descendant dans un répertoire. La -not -path spécification de -not -path descendra toujours dans le répertoire ignoré , mais -not -path sera faux chaque fois que find -not -path chaque fichier.

Problèmes avec -prune

-prune fait ce qu'il a l'intention de faire, mais il y a encore des choses dont vous devez vous soucier quand vous l'utilisez.

  1. find imprime le répertoire élagué.

    • VRAI C'est le comportement prévu, il ne descend pas dedans. Pour éviter d'imprimer le répertoire, utilisez une syntaxe qui l'omet de manière logique.
  2. -prune ne fonctionne qu'avec -print et aucune autre action.

    • NON VRAI -prune fonctionne avec n'importe quelle action sauf -delete . Pourquoi ça ne marche pas avec delete? Pour -delete de travailler, trouver les besoins de parcourir le répertoire dans l'ordre DFS, puisque -delete va d'abord supprimer les feuilles, puis les parents des feuilles, etc ... Mais pour spécifier -prune pour avoir du sens, find besoins pour frapper un répertoire et arrête de le descendre, ce qui n'a aucun sens avec -depth ou -delete on.

Performance

J'ai mis en place un test simple des trois réponses les mieux placées sur cette question (remplacé par -exec bash -c 'echo $0' {} \; pour montrer un autre exemple d'action). Les résultats sont ci-dessous

----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me     702702    
.performance_test/other        2         
----------------------------------------------

> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 23513814

> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 10670141

> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

Conclusion

La syntaxe de f10bit et la syntaxe de Daniel C. Sobral ont toutes deux duré en moyenne 10-25 ms. La syntaxe de GetFree , qui n'utilise pas -prune , a pris 865ms. Donc, oui, c'est un exemple plutôt extrême, mais si vous vous souciez de l'exécution et que vous faites quelque chose de lointain, vous devriez utiliser -prune .

Note La syntaxe de Daniel C. Sobral a été la meilleure des deux syntaxes -prune ; mais, je soupçonne fortement ceci est le résultat d'une certaine mise en cache en tant que commutation de l'ordre dans lequel les deux ont fonctionné dans le résultat opposé, alors que la version non-élagage était toujours la plus lente.

Script de test

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\'  {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup

J'ai essayé la commande ci-dessus, mais aucune de celles utilisant "-prune" ne fonctionne pour moi. Finalement, j'ai essayé ceci avec la commande ci-dessous:

find . \( -name "*" \) -prune -a ! -name "directory"

J'ai trouvé les suggestions sur cette page et beaucoup d'autres pages ne fonctionnent pas sur mon système Mac OS X. Cependant, j'ai trouvé une variation qui fonctionne pour moi.

La grande idée est de rechercher sur le Macintosh HD mais d'éviter de parcourir tous les volumes externes, qui sont pour la plupart des sauvegardes Time Machine, des sauvegardes d'image, des partages montés et des archives, sans les démonter tous, ce qui est souvent irréalisable.

Voici mon script de travail, que j'ai nommé "findit".

#!/usr/bin/env bash
# inspired by http://.com/questions/4210042/exclude-directory-from-find-command Danile C. Sobral
# using special syntax to avoid traversing. 
# However, logic is refactored because the Sobral version still traverses 
# everything on my system

echo ============================
echo find - from cwd, omitting external volumes
date
echo Enter sudo password if requested
sudo find . -not \( \
-path ./Volumes/Archive -prune -o \
-path ./Volumes/Boot\ OS\ X -prune -o \
-path ./Volumes/C \
-path ./Volumes/Data -prune -o \
-path ./Volumes/jas -prune -o \
-path ./Volumes/Recovery\ HD -prune -o \
-path ./Volumes/Time\ Machine\ Backups -prune -o \
-path ./Volumes/SuperDuper\ Image -prune -o \
-path ./Volumes/userland -prune \
\) -name "$1" -print
date
echo ============================
iMac2:~ jas$

Les différents chemins concernent les volumes d'archives externes, Time Machine, les machines virtuelles, les autres serveurs montés, etc. Certains noms de volumes contiennent des espaces.

Un bon test est "findit index.php", car ce fichier se trouve à plusieurs endroits sur mon système. Avec ce script, il faut environ 10 minutes pour rechercher le disque dur principal. Sans ces exclusions, cela prend de nombreuses heures.


J'utilisais find pour fournir une liste de fichiers pour xgettext , et xgettext voulais omettre un répertoire spécifique et son contenu. J'ai essayé beaucoup de permutations de -path combinées avec -prune mais -path incapable d'exclure complètement le répertoire que je voulais allé.

Bien que j'aie pu ignorer le contenu du répertoire que je voulais ignorer, find renvoyé le répertoire lui-même comme l'un des résultats, ce qui a provoqué le xgettext de xgettext (n'accepte pas les répertoires, seulement les fichiers).

Ma solution consistait simplement à utiliser grep -v pour ignorer le répertoire que je ne voulais pas dans les résultats:

find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext

Qu'il y ait ou non un argument pour find qui fonctionnera à 100%, je ne peux pas le dire avec certitude. Utiliser grep était une solution rapide et facile après quelques maux de tête.


Je trouve ce qui suit plus facile à raisonner que d'autres solutions proposées:

find build -not \( -path build/external -prune \) -name \*.js

Cela vient d'un cas d'utilisation réel, où j'ai dû appeler yui-compresseur sur certains fichiers générés par wintersmith, mais laisser de côté les autres fichiers qui doivent être envoyés tels quels.

Inside \( et \) est une expression qui correspond exactement à build/external et qui, en cas de succès, évite de parcourir tout ce qui est en dessous . Ceci est ensuite groupé en une seule expression avec la parenthèse échappée, et préfixé avec -not qui fera que find ignorera tout ce qui a été find par cette expression.

On peut se demander si l'ajout de -not ne fera pas apparaître tous les autres fichiers cachés par -prune , et la réponse est non. La façon dont fonctionne -prune est tout ce qui, une fois qu'il est atteint, les fichiers en dessous de ce répertoire sont définitivement ignorés.

Cela est également facile à développer pour ajouter des exclusions supplémentaires. Par exemple:

find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

Je voulais connaître le nombre de répertoires, les fichiers d'un MB du répertoire actuel - et ce code fait exactement ce que je veux :-)

la source

- ...    2791037 Jun  2  2011 foo.jpg
- ... 1284734651 Mär 10 16:16 foo.tar.gz
- ...          0 Mär 10 15:28 foo.txt
d ...       4096 Mär  3 17:12 HE
d ...       4096 Mär  3 17:21 KU
d ...       4096 Mär  3 17:17 LE
d ...          0 Mär  3 17:14 NO
d ...          0 Mär  3 17:15 SE
d ...          0 Mär  3 17:13 SP
d ...          0 Mär  3 17:14 TE
d ...          0 Mär  3 19:20 UN

le code

format="%s%'12d\n"

find . -type d -not -path "./*/*" | wc -l | awk -v fmt=$format '{printf fmt, " Anzahl Ordner  = ", $1-1}'
find . -type f -not -path "./*/*" | wc -l | awk -v fmt=$format '{printf fmt, " Anzahl Dateien = ", $1}'
  du . -hmS --max-depth=0 | awk -v fmt=$format '{printf fmt, " Groesse (MB)   = ", $1}'

remarque: le format="%s%'12d\n" supplémentaire format="%s%'12d\n" est nécessaire pour que awk les nombres.

le résultat

Anzahl Ordner  =            8
Anzahl Dateien =            3
Groesse (MB)   =        1.228

Mieux vaut utiliser l'action exec que la boucle for :

find . -path "./dirtoexclude" -prune \
    -o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' \;

L' exec ... '{}' ... '{}' \; sera exécuté une fois pour chaque fichier correspondant, en remplaçant les accolades '{}' par le nom de fichier actuel.

Notez que les accolades sont entourées de guillemets simples pour les protéger de l'interprétation en tant que ponctuation de script shell * .

Remarques

* Dans la section find (GNU findutils) 4.4.2 page de manuel find (GNU findutils) 4.4.2


Pour FreeBSD utilisateurs de FreeBSD :

 find . -name '*.js' -not -path '*exclude/this/dir*'

Pour exclure plusieurs répertoires:

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)

Pour ajouter des répertoires, ajoutez -o -path "./dirname/*" :

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)

Mais peut-être devriez-vous utiliser une expression régulière , s'il y a beaucoup de répertoires à exclure.


Pour une solution de travail (testée sur Ubuntu 12.04 (Precise Pangolin)) ...

find ! -path "dir1" -iname "*.mp3"

recherchera des fichiers MP3 dans le dossier et les sous-dossiers en cours, sauf dans le sous-dossier dir1.

Utilisation:

find ! -path "dir1" ! -path "dir2" -iname "*.mp3"

... pour exclure dir1 et dir2


Si les répertoires de recherche ont un motif (dans mon cas la plupart du temps); vous pouvez simplement le faire comme ci-dessous:

find ./n* -name "*.tcl" 

Dans l'exemple ci-dessus; il recherche dans tous les sous-répertoires commençant par "n".


Une option serait d'exclure tous les résultats contenant le nom du répertoire avec grep. Par exemple:

find . -name '*.js' | grep -v excludeddir

Utilisez le commutateur prune, par exemple si vous voulez exclure le répertoire misc ajoutez juste un -path ./misc -prune -o à votre commande find:

find . -path ./misc -prune -o -name '*.txt' -print

Voici un exemple avec plusieurs répertoires:

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

Ici, nous excluons dir1, dir2 et dir3, puisque dans les expressions find c'est une action qui agit sur les critères - -path dir1 -o -path dir2 -o -path dir3 (si dir1 ou dir2 ou dir3), ANDed avec type -d . Une autre action est -o print , juste imprimer.


Vous pouvez utiliser l'option prune pour y parvenir. Comme dans par exemple:

find ./ -path ./beta/* -prune -o -iname example.com -print

Ou l'option grep "grep -v" inverse:

find -iname example.com | grep -v beta

Vous pouvez trouver des instructions détaillées et des exemples dans la commande Linux find commande exclure les répertoires de la recherche .


how-to-use-prune-option-of-find-in-sh est une excellente réponse de Laurence Gonsalves sur comment -prune fonctionne.

Et voici la solution générique:

find /path/to/search                    \
  -type d                               \
    \( -path /path/to/search/exclude_me \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print

Pour éviter de taper /path/to/seach/ plusieurs fois, enroulez la find dans une paire pushd .. popd

pushd /path/to/search;                  \
find .                                  \
  -type d                               \
    \( -path ./exclude_me               \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print;         \
 popd

 find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune




find