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.
Réponses
Trop de publicités?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.
- 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
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.
-
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.
-
-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-delete
sera 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.
-
PAS VRAI.
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