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

find . -name '*.js'

当前回答

使用多模式-o-name时的另一个示例

在根目录/中搜索所有*.tpl、*.tf文件,不包括位于/src/.traform/和/code/中的文件。

$ find / -type f \( -name '*.tf' -o -name '*.tpl' \) \
  -and \( -not -path '/src/.terraform/*' -and -not -path '/code/*' \)


/src/debug.tf
/src/nodegroup-infra.tpl
/src/variables.tf.tpl

我用hyperfine测试了上述命令;该测试是在具有3k个目录和12k个文件的系统上进行的。我认为可以公平地说,它足够快~70ms

Benchmark #1: ./entrypoint.sh
  Time (mean ± σ):      69.2 ms ±   1.4 ms    [User: 22.6 ms, System: 43.6 ms]
  Range (min … max):    66.4 ms …  72.2 ms    42 runs

目录结构示例

/代码/目录树

bash-5.0# tree /code
/code
├── debug.tf
├── entrypoint.sh
├── nodegroup-infra.tpl
├── tftemplate.sh
└── variables.tf.tpl

0 directories, 5 files

/src/目录树

bash-5.0# tree /src
/src
├── Dockerfile
├── debug.tf
├── entrypoint.sh
├── nodegroup-infra.tpl
├── terraform.tfstate
├── terraform.tfstate.backup
└── variables.tf.tpl

0 directories, 7 files

/根目录树摘要

$ tree /
...
3382 directories, 12164 files

其他回答

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

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。

您也可以使用

find  -type f -not -name .directoryname -printf "%f\n"

如果有人想在Makefile中添加find命令,下面是我们排除目录的方法

! -路径“*/directoryName/*”

以下是格式化所有golang文件的示例,不包括protobuf go文件和供应商目录下的所有文件:

find . ! -name '*.pb.go' -name '*.go' ! -path "*/vendor/*" -exec gofmt -s -w '{}' +

如果搜索目录有模式(在大多数情况下);您可以简单地如下所示:

find ./n* -name "*.tcl" 

在上述示例中;它搜索所有以“n”开头的子目录。

避免打印修剪后的目录的一个好技巧是在-或-修剪后的右侧使用-print(也适用于-exec)。例如

find . -path "*/.*" -prune -or -iname "*.j2"

将打印当前目录下所有文件的路径,扩展名为“.j2”,跳过所有隐藏目录。Neat。但它也将打印每个正在跳过的目录的完整路径,如上所述。然而,以下内容没有。。。

find . -path "*/.*" -prune -or -iname "*.j2" -print

因为逻辑上有一个隐藏的,在iname运算符之后,在print之前。由于操作的布尔顺序和关联性,这将其绑定到-or子句的右部分。但医生说,如果没有指定它(或它的任何表亲…-print0等),就会有一个隐藏的打印。那么,为什么不是打印的左边部分呢?显然(而且我从第一次阅读手册页时就不明白这一点),如果没有-print或-exec ANYWHERE,那么这是正确的,在这种情况下,-print在逻辑上分散开来,使得所有内容都被打印出来。如果在任何子句中都表达了一个打印样式操作,那么所有隐藏的逻辑操作都将消失,您只能得到指定的内容。现在坦率地说,我可能更喜欢相反的方式,但如果只使用描述性运算符,那么查找显然不会起作用,所以我想这是有意义的。如上所述,这也适用于-exec,因此下面为每个具有所需扩展名的文件提供了完整的ls-la列表,但没有列出每个隐藏目录的第一级。。。

find . -path "*/.*" -prune -or -iname "*.j2" -exec ls -la -- {} +

对我(以及本线程中的其他人)来说,find语法很快就变得非常复杂,所以我总是插入括号以确保我知道什么绑定到什么,所以我通常创建一个用于类型能力的宏,并形成所有这样的语句,如。。。

find . \( \( ... description of stuff to avoid ... \) -prune \) -or \
\( ... description of stuff I want to find ... [ -exec or -print] \)

这样把世界分成两部分是很难出错的。我希望这会有所帮助,尽管似乎不太可能有人读到第30个以上的答案并投票支持,但我们可以希望