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

find . -name '*.js'

当前回答

我在这个页面上找到了建议,很多其他页面在我的Mac OS X系统上都不起作用。然而,我发现了一种对我有用的变体。

大的想法是搜索Macintosh HD,但避免遍历所有外部卷,这些卷主要是Time Machine备份、映像备份、装载的共享和存档,但不必全部卸载,这通常是不切实际的。

这是我的工作脚本,我将其命名为“findit”。

#!/usr/bin/env bash
# inspired by http://stackoverflow.com/questions/4210042/exclude-directory-from-find-command Danile C. Sobral
# using special syntax to avoid traversing. 
# However, logic is refactored because the Sobral version still traverses 
# everything on my system

echo ============================
echo find - from cwd, omitting external volumes
date
echo Enter sudo password if requested
sudo find . -not \( \
-path ./Volumes/Archive -prune -o \
-path ./Volumes/Boot\ OS\ X -prune -o \
-path ./Volumes/C \
-path ./Volumes/Data -prune -o \
-path ./Volumes/jas -prune -o \
-path ./Volumes/Recovery\ HD -prune -o \
-path ./Volumes/Time\ Machine\ Backups -prune -o \
-path ./Volumes/SuperDuper\ Image -prune -o \
-path ./Volumes/userland -prune \
\) -name "$1" -print
date
echo ============================
iMac2:~ jas$

不同的路径与外部存档卷、Time Machine、虚拟机、其他装载的服务器等有关。一些卷名中有空格。

一个好的测试运行是“finditindex.php”,因为该文件出现在我的系统中的许多地方。使用此脚本,搜索主硬盘大约需要10分钟。如果没有这些例外,这需要很多小时。

其他回答

如何在sh中使用find的prune选项是Laurence Gonsalves关于prune如何工作的一个很好的答案。

下面是通用解决方案:

find /path/to/search                    \
  -type d                               \
    \( -path /path/to/search/exclude_me \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print

要避免多次键入/path/To/seach/,请将查找包装在pushd中。。popd对。

pushd /path/to/search;                  \
find .                                  \
  -type d                               \
    \( -path ./exclude_me               \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print;         \
 popd

这适合我在Mac上使用:

find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune

它将排除带有php后缀的搜索名称的供应商和app/cache-dir。

find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'

似乎与

find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)

并且更容易记住IMO。

而不是:

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done

…并且由于您没有定义要排除的子目录,因此可以使用:

for file in $(find *.js -maxdepth 0 -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done

此语法将排除所有子目录。

看看下面的示例:在tmp目录下,我有一个巨大的“归档”子目录,其中包含17000-4640=12360个文件。此目录位于慢速NFS上。虽然第一个语法扫描“archive”子目录并执行得很差,但第二个语法只扫描我当前目录中包含的“*pdf”文件并执行。。。没那么糟。

[tmp]$ time (find . -name "*pdf" | wc -l)
17000

real    0m40.479s
user    0m0.423s
sys     0m5.606s

[tmp]$ time (find *pdf -maxdepth 0 -name "*pdf" | wc -l)
4640

real    0m7.778s
user    0m0.113s
sys     0m1.136s

第二种语法非常有趣:在下面的示例中,我想检查文件or60runm50958.pdf是否存在,并且超过20分钟。亲自看看第二种语法是如何更有效的。这是因为它避免了扫描存档子目录。

[tmp]$ time find . -name or60runm50958.pdf -mmin +20
./or60runm50958.pdf

real    0m51.145s
user    0m0.529s
sys     0m6.243s

[tmp]$ time find or60runm50958.pdf -maxdepth 0 -name or60runm50958.pdf -mmin +20
or60runm50958.pdf

real    0m0.004s
user    0m0.000s
sys     0m0.002s

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

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。