Il y a manifestement une certaine confusion quant à la syntaxe à utiliser pour sauter un répertoire.
Opinion de GNU
To ignore a directory and the files under it, use -prune
Extrait de la page de manuel GNU find
Raisonnement
-prune
arrête find
de descendre dans un répertoire. Il suffit de spécifier -not -path
descendront encore dans le a sauté mais -not -path
sera faux lorsque find
teste chaque fichier.
Questions relatives à -prune
-prune
fait ce qu'il est censé faire, mais il y a encore des choses auxquelles vous devez faire attention lorsque vous l'utilisez.
-
find
imprime le répertoire élagué.
-
VRAI C'est le comportement souhaité, mais il ne s'y abaisse pas. Pour éviter d'imprimer complètement le répertoire, utilisez une syntaxe qui l'omet logiquement.
-
-prune
ne fonctionne qu'avec -print
et aucune autre action.
-
PAS VRAI .
-prune
fonctionne avec toutes les actions sauf -delete
. Pourquoi ça ne marche pas avec la suppression ? Pour -delete
pour fonctionner, find doit 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
doit atteindre un répertoire et arrêter de le descendre, ce qui n'a clairement aucun sens avec -depth
o -delete
sur.
Performance
J'ai mis en place un test simple des trois réponses les plus votées à cette question (remplacées par les réponses suivantes -print
con -exec bash -c 'echo $0' {} \;
pour montrer un autre exemple d'action). Les résultats sont les suivants
----------------------------------------------
# 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 sites La syntaxe de f10bit y La syntaxe de Daniel C. Sobral a pris 10-25ms pour s'exécuter en moyenne. La syntaxe de GetFree qui n'utilise pas -prune
a pris 865 ms. Donc, oui, c'est un exemple plutôt extrême, mais si vous vous souciez du temps d'exécution et que vous faites quelque chose d'un peu intensif, vous devriez utiliser -prune
.
Note La syntaxe de Daniel C. Sobral a réalisé la meilleure performance des deux -prune
mais je soupçonne fortement qu'il s'agit du résultat d'une mise en cache, car en changeant l'ordre dans lequel les deux s'exécutent, on obtient le résultat inverse, alors que la version sans prune est toujours la plus lente.
Test script
#!/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
11 votes
Quel est le répertoire que vous devez exclure ?
13 votes
Il est préférable d'utiliser
find ... | while read -r file ...
. De plus, il est préférable d'accepter et d'upvoter les réponses.0 votes
Alors que la lecture est lente, le for in est plus rapide
18 votes
@mpapis pendant la lecture gère correctement les lignes complètes avec des espaces.
0 votes
J'ai essayé d'exclure le répertoire /proc pour éviter que des erreurs de refus de permission ne masquent mes résultats, mais cela n'a pas fonctionné ; voici comment j'y suis parvenu : stackoverflow.com/questions/762348/
0 votes
Find . -name "*.so" -type f (ignore les dossiers)
0 votes
@Jean-PhilippePellet Qu'est-ce que cela signifie qu'il gère correctement les lignes complètes avec des espaces ? Pouvez-vous donner un exemple où
for file in $(find ...); do ...; done
échouerait ?1 votes
Il suffit de l'exécuter dans un dossier contenant des fichiers avec des espaces dans leurs noms :
for file in $(find .); do echo "$file"; done
. Les noms avec des espaces sont divisés, ce que nous ne voulons pas.0 votes
Rappelez-vous de ne pas mettre "/" à la fin ou cela retournera tous les fichiers du dossier... donc comme ceci ; find /home/mquick/watch_folder -not ( -path "/home/mquick/watch_folder/aws_restore_tool.bash_restore_folder" -prune ) -exec bash -c 'echo '$0'' {} \ ;
0 votes
Utilisez
-path -prune
pour exclure le contenu du répertoire, et ajoutez-type f
supprimer le nom du répertoire indésirable lui-même des résultats :find <srcdir> -path '*/ignoredirname' -prune -type f -o -name '*.js'
0 votes
Il existe une alternative moderne à
find
: fdfind dontexcludes by default hidden files
. Dois-je poster une nouvelle réponse ?