1523 votes

exclure répertoire de trouver. commande

Je suis en train d’exécuter une commande de rechercher tous les fichiers javascript, mais j’ai besoin d’exclure un répertoire spécifique. Voici le code de recherche que nous utilisons.

2076voto

GetFree Points 4971

Toutes les réponses à l’aide de `` ont tort.
La bonne façon est :

1305voto

f10bit Points 2087

Utiliser le pruneau de l'interrupteur, par exemple, si vous voulez exclure le répertoire misc juste ajouter un -path ./misc -prune -o de 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 exclure dir1, dir2 et dir3, puisque, en find expressions c'est une action, qui agit sur les critères d' -path dir1 -o -path dir2 -o -path dir3 (si dir1 ou dir2 ou dir3), ANDed avec type -d. La poursuite de l'action est - -o print, il suffit d'imprimer.

492voto

Daniel C. Sobral Points 159554

- Je trouver la suite plus facile de raisonner sur que les autres solutions proposées:

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

Cela vient d'un réel de cas d'utilisation, l'endroit où je devais appeler yui-compresseur sur certains fichiers générés par wintersmith, mais laissez de côté les autres fichiers qui doivent être envoyé comme-est.

À l'intérieur d' \( et \) est une expression qui correspond exactement build/external, et, en cas de succès, d'éviter la traversée rien en dessous. C'est ensuite regroupés en une seule expression avec l'échappé de la parenthèse, et avec le préfixe -not qui feront find sauter quoi que ce soit qui a été reconnue par cette expression.

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

C'est aussi facile de l'étendre à ajouter des exclusions. Par exemple:

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

228voto

BroSlow Points 3691

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

GNU Avis

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

À partir de la GNU trouver l'homme page

Le raisonnement

-prune s'arrête find de sombrer dans un répertoire. Juste en précisant -not -path sera toujours descendre dans le sauté de répertoire, mais -not -path sera false dès qu' find tests de chaque fichier.

Problèmes avec -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 taillés répertoire.

    • VRAI Que c'est un comportement intentionnel, il n'a tout simplement pas descendre en elle. Pour éviter l'impression de l'annuaire au total, l'utilisation d'une syntaxe qui, logiquement, omet-il.
  2. -prune ne fonctionne qu'avec des -print et pas d'autres actions.

    • PAS VRAI. -prune fonctionne avec n'importe quelle action, sauf -delete. Pourquoi ne pas travailler avec les supprimer? Pour -delete à travailler, à trouver doit parcourir le répertoire dans DFS ordre, depuis -deletesera d'abord supprimer les feuilles, puis les parents de feuilles, etc... Mais pour la spécification -prune à avoir un sens, find des besoins de frapper un répertoire et de l'arrêt de descente, ce qui clairement n'a pas de sens avec -depth ou -delete sur.

Performance

J'ai créé un simple test des trois premiers upvoted des réponses sur cette question (remplacé -print avec -exec bash -c 'echo $0' {} \; pour montrer une autre action, par exemple). 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

Les deux f10bit de la syntaxe et Daniel C. Sobral de la syntaxe a fallu 10-25ms à courir sur la moyenne. GetFree de la syntaxe, qui permet de ne pas utiliser -prune, a pris 865ms. Donc, oui, c'est un exemple extrême, mais si vous vous souciez de l'exécution et sont en train de faire quelque chose à distance intensif vous devez utiliser -prune.

Remarque Daniel C. Sobral de la syntaxe réalisé la meilleure des deux, -prune syntaxes; mais, je soupçonne fortement que c'est le résultat d'une mise en cache comme le changement de l'ordre dans lequel les deux couru abouti à l'effet inverse, alors que le non-prune version est 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

41voto

mpapis Points 32015

Je préfère le `` notation... c’est plus lisible :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X