Comment exclure un répertoire en trouver. commande

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

voici le code find que nous utilisons.

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done
946
demandé sur leiyc 2010-11-18 01:57:02

30 réponses

utilisez le commutateur prune, par exemple si vous voulez exclure le répertoire misc ajoutez simplement un -path ./misc -prune -o à votre commande de recherche:

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 find expressions c'est une action, qui agit sur les critères -path dir1 -o -path dir2 -o -path dir3 (si dir1 ou dir2 ou dir3), et avec type -d . Une autre action est -o print , juste imprimer.

727
répondu f10bit 2017-01-27 15:30:06

si -prune ne fonctionne pas pour vous, ce sera:

find -name "*.js" -not -path "./directory/*"
1567
répondu GetFree 2016-11-06 04:03:31

je trouve que les éléments suivants sont plus faciles à raisonner que d'autres solutions proposées:

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

cela vient d'un cas d'utilisation réelle, où j'ai dû appeler Yui-compresseur sur certains fichiers générés par wintersmith, mais en laissant de côté d'autres fichiers qui doivent être envoyés tels quels.

à l'Intérieur \( et \) est une expression qui correspond à exactement build/external (il not match si vous avez fait find ./build , par exemple -- vous devez le changer en ./build/external dans ce cas), et will, on success, éviter de traverser quoi que ce soit en dessous de . Elle est alors groupée en une seule expression avec la parenthèse échappée, et préfixée avec -not qui fera que find sautera tout ce qui a été apparié par cette expression.

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

qui est également facile à étendre pour ajouter des exclusions supplémentaires. Par exemple:

find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js
358
répondu Daniel C. Sobral 2018-05-21 06:35:51

il y a clairement une certaine confusion ici quant à la syntaxe préférée pour sauter un répertoire.

GNU Avis

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

De la GNU trouver l'homme page

raisonnement

-prune empêche find de descendre dans un répertoire. Juste en précisant -not -path descendra toujours dans le a sauté , mais -not -path sera faux chaque fois que find teste chaque fichier.

Problèmes avec les -prune

-prune fait ce qu'il veut faire, mais il reste certaines choses que vous devez prendre soin lors de l'utilisation.

  1. find imprime le répertoire pruned.

    • vrai c'est un comportement intentionnel, il ne descend tout simplement pas en elle. Pour éviter d'imprimer le répertoire, utilisez une syntaxe qui l'omet logiquement.
  2. -prune fonctionne uniquement avec -print et aucune autre action.

    • PAS VRAI . -prune fonctionne avec toute action à l'exception de -delete . pourquoi ça ne marche pas avec delete? pour -delete pour travailler, trouver doit parcourir le répertoire dans L'ordre DFS, puisque -delete supprimera d'abord les feuilles, puis les parents des feuilles, etc... Mais pour spécifier -prune pour avoir du sens, find doit frapper un répertoire et arrêter de le descendre, ce qui n'a clairement aucun sens avec -depth ou -delete sur.

Performance

j'ai mis en place un test simple des trois réponses complémentaires sur cette question (remplacé -print par -exec bash -c 'echo " 1519220920 "' {} \; pour montrer un autre exemple d'action). Les résultats sont en dessous de

----------------------------------------------
# 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 ""151910920""' {} \;
.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 ""151910920""' {} \;
.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 ""151910920""' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

Conclusion

les Deux f10bit de la syntaxe et Daniel C. Sobral de la syntaxe a pris 10-25ms pour courir sur la moyenne. la syntaxe de GetFree , qui n'utilise pas -prune , a pris 865ms. Donc, oui c'est un exemple assez extrême, mais si vous vous souciez du temps d'exécution et que vous faites quelque chose d'intensif à distance vous devriez utiliser -prune .

Note la syntaxe de Daniel C. Sobral a réalisé le meilleur des deux syntaxes -prune ; mais, je soupçonne fortement que cela est le résultat d'une certaine mise en cache comme commutation de l'ordre dans la version non-prune a toujours été 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 ""151920920""'  {} \;
}

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

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

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
159
répondu BroSlow 2017-05-23 12:34:54

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

find . -name '*.js' | grep -v excludeddir
45
répondu Joshua 2010-11-17 23:01:24

je préfère la notation -not ... c'est plus lisible:

find . -name '*.js' -and -not -path directory
38
répondu mpapis 2013-04-03 11:44:25

utilisez l'option-prune. Donc, quelque chose comme:

find . -type d -name proc -prune -o -name '*.js'

Le "- type d -name proc -prune " seulement rechercher les répertoires nommés proc à exclure.

L'option '-o' est un 'OU' opérateur.

18
répondu Drew Frezell 2010-11-17 23:07:40

C'est la seule qui a fonctionné pour moi.

find / -name NameOfFile ! -path '*/Directory/*'

recherche de" NameOfFile "à l'exclusion de"Directory". Mettre l'accent sur les étoiles * .

14
répondu DimiDak 2018-09-30 08:27:46

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 non dedans ".*" chemins:

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"
13
répondu user1882879 2016-01-18 17:06:19

-prune fonctionne certainement et est la meilleure réponse parce qu'il empêche de descendre dans le dir que vous voulez exclure. -not -path qui recherche toujours le dir exclu, il n'affiche tout simplement pas le résultat, ce qui pourrait être un problème si le dir exclu est monté en volume réseau ou si vous n'avez pas de permissions.

la partie délicate est que find est très particulier sur l'ordre des arguments, donc si vous ne les obtenez pas juste, votre commande peut pas de travail. L'ordre des arguments est généralement comme tel:

find {path} {options} {action}

{path} : mettez tous les arguments relatifs au chemin en premier, comme . -path './dir1' -prune -o

{options} : j'ai le plus de succès en mettant -name, -iname, etc comme dernière option dans ce groupe. Par exemple: -type f -iname '*.js'

{action} :vous voudrez ajouter -print en utilisant -prune

voici un exemple pratique:

# setup test
mkdir dir1 dir2 dir3
touch dir1/file.txt; touch dir1/file.js
touch dir2/file.txt; touch dir2/file.js
touch dir3/file.txt; touch dir3/file.js

# search for *.js, exclude dir1
find . -path './dir1' -prune -o -type f -iname '*.js' -print

# search for *.js, exclude dir1 and dir2
find . \( -path './dir1' -o -path './dir2' \) -prune -o -type f -iname '*.js' -print
10
répondu wisbucky 2017-11-29 19:58:44

l'approche-path-prune fonctionne aussi avec des caractères génériques dans le path. Voici une instruction find qui va trouver les répertoires d'un serveur git desservant plusieurs repositioires Git en laissant de côté les répertoires internes git:

find . -type d \
   -not \( -path */objects -prune \) \
   -not \( -path */branches -prune \) \
   -not \( -path */refs -prune \) \
   -not \( -path */logs -prune \) \
   -not \( -path */.git -prune \) \
   -not \( -path */info -prune \) \
   -not \( -path */hooks -prune \)  
8
répondu Wolfgang Fahl 2017-08-30 04:05:44

pour une solution de travail (Testée sur Ubuntu 12.04 (Pangolin précis))...

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

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

utiliser:

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

... pour exclure dir1 et dir2

7
répondu james dupin 2015-10-08 19:20:38

pour exclure plusieurs répertoires:

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

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

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

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

6
répondu JBENOIT 2015-10-08 19:21:32

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

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

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

find -iname example.com | grep -v beta

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

6
répondu Siju V 2016-06-25 10:48:24

il y a beaucoup de bonnes réponses, il m'a juste fallu un certain temps pour comprendre à quoi servait chaque élément de la commande et la logique derrière elle.

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

find va commencer à rechercher des fichiers et des répertoires dans le répertoire courant, d'où le find . .

l'option -o représente un et et sépare les deux parties de la commande:

[ -path ./misc -prune ] OR [ -name '*.txt' -print ]

Tout répertoire ou fichier qui est pas ./ misc directory ne passera pas le premier test -path ./misc . Mais ils seront testés par rapport à la seconde expression. Si leur nom correspond au modèle *.txt ils sont imprimés, à cause de l'option -print .

quand find atteint le ./ misc directory, ce répertoire ne satisfait que la première expression. Ainsi ,l'option -prune sera appliquée. Il indique la commande "find" à not explorer ce répertoire. Tout fichier ou répertoire ./misc ne seront même pas exploré par trouver, ne sera pas testée contre la deuxième partie de l'expression et ne sera pas imprimée.

6
répondu Istopopoki 2018-03-07 10:20:53

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

bien que j'aie pu ignorer le contenu du répertoire que je voulais ignorer, find a ensuite retourné le répertoire lui-même comme l'un des résultats, qui a fait planter xgettext en conséquence (n'accepte pas les répertoires, seulement les fichiers).

ma solution était simplement d'utiliser grep -v pour sauter 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.

3
répondu Lemmings19 2013-05-30 16:56:24
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'

semble fonctionner de la même façon que

find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)

et est plus facile à se rappeler IMO.

3
répondu Funkodebat 2014-08-29 20:41:15
 find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune
2
répondu The Archetypal Paul 2010-11-17 23:06:37

aucune des réponses précédentes n'est bonne sur Ubuntu. Essayez ceci:

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

j'ai trouvé ce ici

2
répondu sixro 2017-04-13 12:22:42

cela me convient sur un Mac:

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

Il va exclure vendor et app/cache dir de recherche nom suffixé par php .

2
répondu jiahut 2015-10-08 19:22:11

pour ceux d'entre vous sur les anciennes versions D'UNIX qui ne peuvent pas utiliser - chemin ou - pas

testé sur SunOS 5.10 bash 3.2 et SunOS 5.11 bash 4.4

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f
2
répondu JaredTS486 2017-11-16 19:56:00

how-to-use-prune-option-de-trouver-en-sh est une excellente réponse par Laurence Gonsalves, comment -prune .

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, envelopper le 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
1
répondu go2null 2017-05-23 12:02:49

j'ai trouvé le nom des fonctions dans les fichiers c sources exclude *.o et exclure *.swp et exclude (pas de fichier régulier) et exclude la sortie dir avec cette commande:

find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach
1
répondu Ivan Ivanovich 2015-10-08 19:23:00

mieux 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 '{}' \;

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

notez que les supports sont inclus dans des guillemets simples pour les protéger de l'interprétation en tant que ponctuation de scripts shell * .


Notes

* de la section Exemples de la page de manuel find (GNU findutils) 4.4.2 151970920"

1
répondu Alberto 2016-01-15 14:19:02

j'ai essayé la commande ci-dessus, mais aucun de ceux qui utilisent "- prune" ne fonctionne pour moi. Finalement, j'ai essayé avec la commande ci-dessous:

find . \( -name "*" \) -prune -a ! -name "directory"
1
répondu Jolly Liu 2017-05-12 08:56:05

pour ce dont j'avais besoin cela a fonctionné comme ceci, trouver landscape.jpg dans tous les serveurs à partir de la racine et à l'exclusion de la recherche dans /var répertoire:

find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg

"151930920 la liste de tous les d irectories dans /

grep -v /var exclut ` / var" de la liste

xargs -I '{}' find '{}' -name landscape.jpg exécutez n'importe quelle commande, comme find avec chaque répertoire / résultat de la liste

1
répondu adrianTNT 2018-03-27 10:26:37

cela fonctionne parce que find TESTS les fichiers pour le pattern * foo* ":

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

mais il ne pas travail si vous n'utilisez pas un modèle ( find ne TEST le fichier). Donc find ne fait aucun usage de son ex-évalué " vrai " & " faux " bool. Exemple pour cas d'utilisation sans travail avec la notation ci-dessus:

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

il n'y a pas de find test! Donc si vous avez besoin de trouver des fichiers sans aucun motif correspondant utilisez le-prune. En outre, par l'utilisation de prune find est toujours plus rapide alors qu'il saute vraiment que les répertoires au lieu de correspondre ou mieux ne pas correspondre. 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

concerne

0
répondu d0n 2014-12-31 11:44:32

pour FreeBSD utilisateurs:

 find . -name '*.js' -not -path '*exclude/this/dir*'
0
répondu Richard Bartisek 2015-10-08 19:28:36

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".

0
répondu Prince Bhanwra 2016-04-22 09:57:41

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

la grande idée est de rechercher le Macintosh HD mais d'éviter de traverser tous les volumes externes, qui sont la plupart du temps des sauvegardes de Machine à remonter le temps, des sauvegardes d'image, des partages montés, et des archives, mais sans avoir à les démonter tous, ce qui est souvent peu pratique.

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

#!/usr/bin/env bash
# inspired by /q/how-to-exclude-a-directory-in-find-command-63831/"" -print
date
echo ============================
iMac2:~ jas$

les différents chemins ont à faire avec les volumes d'archives externes, machine temporelle, Machines virtuelles, autres serveurs montés, et ainsi de suite. Certains noms de volumes comportent des espaces.

un bon essai est " findit index.php", parce que ce fichier se trouve à de nombreux endroits sur mon système. Avec ce script, il faut environ 10 minutes pour chercher le disque dur principal. Sans ces exclusions, ça prend des heures.

0
répondu Jeffrey Simon 2016-10-06 15:33:16