使用find搜索*.js文件时,如何排除特定目录?
find . -name '*.js'
使用find搜索*.js文件时,如何排除特定目录?
find . -name '*.js'
当前回答
这是我用来排除某些路径的格式:
$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"
我使用此命令查找不在“.*”路径中的所有文件:
$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"
其他回答
我使用find为xgettext提供文件列表,并希望省略特定目录及其内容。我尝试了许多-path与-prune组合的排列,但无法完全排除我想要删除的目录。
虽然我能够忽略我想要忽略的目录内容,但find随后将目录本身作为结果之一返回,结果导致xgettext崩溃(不接受目录,只接受文件)。
我的解决方案是简单地使用grep-v跳过结果中不需要的目录:
find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext
我不能肯定,是否有一个论据支持这一发现,它能100%奏效。在头痛之后,使用grep是一个快速而简单的解决方案。
不确定这是否能涵盖所有边缘情况,但以下内容将非常简单明了:
ls-1 | grep-v-e ddl-e docs | xargs rm-rf
这将从当前目录excpet“ddls”和“docs”中删除所有文件/目录。
我发现以下内容比其他建议的解决方案更容易理解:
find build -not \( -path build/external -prune \) -name \*.js
# you can also exclude multiple paths
find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js
重要提示:在-path之后键入的路径必须与find在没有排除的情况下打印的路径完全匹配。如果这句话让您感到困惑,您只需确保在整个命令中使用完整路径,如下所示:find/full/path/-not\(-path/full/path/exclude/this-sprune\)。。。。如果您想更好地理解,请参见注释[1]。
Inside\(和\)是一个表达式,它将与build/external完全匹配(请参见上面的重要注释),并且在成功后,将避免遍历下面的任何内容。然后将其分组为带有转义括号的单个表达式,并以-not作为前缀,这将使find跳过该表达式匹配的任何内容。
有人可能会问,添加-not是否不会使所有其他被-previe隐藏的文件重新出现,答案是否定的。
这来自一个实际的用例,我需要对温特史密斯生成的一些文件调用yui压缩程序,但忽略了需要按原样发送的其他文件。
注[1]:如果您想排除/tmp/foo/bar,并且运行find时类似于“find/tmp\(…)”,那么您必须指定-path/tmp/foo/bar。另一方面,如果您运行find,类似于cd/tmp;find.\(…),那么必须指定-path。/foo/bbar。
如果有人想在Makefile中添加find命令,下面是我们排除目录的方法
! -路径“*/directoryName/*”
以下是格式化所有golang文件的示例,不包括protobuf go文件和供应商目录下的所有文件:
find . ! -name '*.pb.go' -name '*.go' ! -path "*/vendor/*" -exec gofmt -s -w '{}' +
对于跳过目录的首选语法应该是什么,这里显然有些混乱。
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