使用find搜索*.js文件时,如何排除特定目录?
find . -name '*.js'
使用find搜索*.js文件时,如何排除特定目录?
find . -name '*.js'
当前回答
对于跳过目录的首选语法应该是什么,这里显然有些混乱。
GNU意见
To ignore a directory and the files under it, use -prune
从GNU查找手册页
推理
-prune阻止find下降到目录中。仅指定-not-path仍将进入跳过的目录,但每当查找测试每个文件时,-not-paath将为false。
与-prune有关的问题
-梅干做了它想要做的事情,但在使用它时仍需要注意一些事情。
find打印修剪后的目录。TRUE这是预期的行为,它只是没有下降到目录中。为了避免完全打印目录,请使用逻辑上省略它的语法。-prune只适用于-print,不适用于其他操作。不正确-prune适用于除-delete之外的任何操作。为什么它不能与delete一起使用?要使-delete起作用,find需要按DFS顺序遍历目录,因为-delete将首先删除树叶,然后删除树叶的父级,等等。但是,要指定-sprune以使其合理,find必须命中一个目录并停止其降序,这显然在启用-dedepth或-delete时没有意义。
表演
我对这个问题的三个排名靠前的答案进行了简单的测试(用-exec bash-c'echo$0'{}\;替换-print以显示另一个动作示例)。结果如下
----------------------------------------------
# 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
结论
f10bit的语法和Daniel C.Sobral的语法平均运行时间为10-25ms。GetFree的语法不使用-prune,耗时865ms。所以,是的,这是一个相当极端的例子,但如果您关心运行时间,并且正在做任何远程密集的事情,那么您应该使用-prune。
注意Daniel C.Sobral的语法在两种删减语法中表现得更好;但是,我强烈怀疑这是某些缓存的结果,因为切换两个运行的顺序会导致相反的结果,而非修剪版本总是最慢的。
测试脚本
#!/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
其他回答
如果搜索目录有模式(在大多数情况下);您可以简单地如下所示:
find ./n* -name "*.tcl"
在上述示例中;它搜索所有以“n”开头的子目录。
对于跳过目录的首选语法应该是什么,这里显然有些混乱。
GNU意见
To ignore a directory and the files under it, use -prune
从GNU查找手册页
推理
-prune阻止find下降到目录中。仅指定-not-path仍将进入跳过的目录,但每当查找测试每个文件时,-not-paath将为false。
与-prune有关的问题
-梅干做了它想要做的事情,但在使用它时仍需要注意一些事情。
find打印修剪后的目录。TRUE这是预期的行为,它只是没有下降到目录中。为了避免完全打印目录,请使用逻辑上省略它的语法。-prune只适用于-print,不适用于其他操作。不正确-prune适用于除-delete之外的任何操作。为什么它不能与delete一起使用?要使-delete起作用,find需要按DFS顺序遍历目录,因为-delete将首先删除树叶,然后删除树叶的父级,等等。但是,要指定-sprune以使其合理,find必须命中一个目录并停止其降序,这显然在启用-dedepth或-delete时没有意义。
表演
我对这个问题的三个排名靠前的答案进行了简单的测试(用-exec bash-c'echo$0'{}\;替换-print以显示另一个动作示例)。结果如下
----------------------------------------------
# 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
结论
f10bit的语法和Daniel C.Sobral的语法平均运行时间为10-25ms。GetFree的语法不使用-prune,耗时865ms。所以,是的,这是一个相当极端的例子,但如果您关心运行时间,并且正在做任何远程密集的事情,那么您应该使用-prune。
注意Daniel C.Sobral的语法在两种删减语法中表现得更好;但是,我强烈怀疑这是某些缓存的结果,因为切换两个运行的顺序会导致相反的结果,而非修剪版本总是最慢的。
测试脚本
#!/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
您也可以使用
find -type f -not -name .directoryname -printf "%f\n"
我使用find为xgettext提供文件列表,并希望省略特定目录及其内容。我尝试了许多-path与-prune组合的排列,但无法完全排除我想要删除的目录。
虽然我能够忽略我想要忽略的目录内容,但find随后将目录本身作为结果之一返回,结果导致xgettext崩溃(不接受目录,只接受文件)。
我的解决方案是简单地使用grep-v跳过结果中不需要的目录:
find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext
我不能肯定,是否有一个论据支持这一发现,它能100%奏效。在头痛之后,使用grep是一个快速而简单的解决方案。
我在C源文件exclude*.o和exclude*.swp以及exclude(非常规文件)和exclude-dir输出中找到了函数名:
find . \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach