使用find搜索*.js文件时,如何排除特定目录?

find . -name '*.js'

当前回答

我发现以下内容比其他建议的解决方案更容易理解:

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。

其他回答

我认为自己是一个狂欢爱好者,但是。。。在过去的两年中,我们没有找到一个适合bash用户的解决方案。我所说的“用户友好”是指只需一次调用,这不需要我记住复杂的语法+我可以使用与以前相同的find语法,因此以下解决方案最适合那些^^^

复制粘贴到shell中,并将~/.bash_aliases作为源代码:

cat << "EOF" >> ~/.bash_aliases
# usage: source ~/.bash_aliases , instead of find type findd + rest of syntax
findd(){
   dir=$1; shift ;
   find  $dir -not -path "*/node_modules/*" -not -path "*/build/*" \
      -not -path "*/.cache/*" -not -path "*/.git/*" -not -path "*/venv/*" $@
}
EOF

当然,为了添加或删除要排除的目录,您必须使用您选择的目录编辑此别名func。。。

对于那些在旧版本UNIX上无法使用-path或-not的用户

在SunOS 5.10 bash 3.2和SunOS 5.11 bash 4.4上测试

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune

如果-prune对你不起作用,这将:

find -name "*.js" -not -path "./directory/*"

注意:需要遍历所有不需要的目录。

如果您正在寻找一个高性能的答案,那么它就是:

find . -type d -name node_modules -prune -false -o -type f

使用-false排除node_modules本身。

在node_modules中包含10000个文件的目录中,它将比非路径方法快3倍。

find . -type f -not -path '*node_modules*'

如果node_modules有更多的文件,您将获得更高的性能。