如何在find中排除目录。命令


1378

我正在尝试find为所有JavaScript文件运行命令,但是如何排除特定目录?

这是find我们正在使用的代码。

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

10
您需要排除的目录是什么?
原型保罗,2010年

11
最好使用find ... | while read -r file ...。另外,最好接受并支持答案。
暂停,直到另行通知。

虽然读取速度较慢,但​​输入速度较快
mpapis 2010年

18
正确读取时,@ mpapis可以用空格处理全行。
让-菲利普·佩莱

1
只需在文件名中带有空格的文件夹中运行此文件即可for file in $(find .); do echo "$file"; done。带空格的名称被拆分,这是我们不希望的。
Jean-Philippe Pellet

Answers:


1139

使用-prune开关。例如,如果要排除misc目录,只需将a添加-path ./misc -prune -o到您的find命令中:

find . -path ./misc -prune -o -name '*.txt' -print

这是带有多个目录的示例:

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

在这里,我们排除了dir1dir2dir3,因为在find表达式中,这是一个作用于条件-path dir1 -o -path dir2 -o -path dir3(如果是dir1dir2dir3)的操作,并与进行与type -d

进一步的操作是-o print,仅打印。


89
嗯 这对我也不起作用,因为它将在输出中包含被忽略的目录“ ./misc”。
Theuni 2012年

84
@Theuni它可能对您不起作用,因为您没有-print在之后显式添加(或任何其他操作)-name。在这种情况下,两个“面”都将-o结束打印,而如果使用-print,则仅打印该面。
Daniel C. Sobral

4
来自联机帮助页:Because -delete implies -depth, you cannot usefully use -prune and -delete together.因此,如果要从删除中排除特定目录,该如何使用find进行删除?
雅尼斯·埃默里斯(JānisElmeris)2013年

15
要从结果中删除整个目录本身,请使用:find . -not -path "./.git*"。使用./dir*而不是./dir/*删除目录以及输出中的内容。
micahblu 2014年

64
这个问题和答案中的困惑表明,查找用户界面与人们所需的匹配程度有多么差。
Johannes Overmann '17

1931

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

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

警告:需要遍历所有不需要的目录。


86
接受的答案中有一条评论指出了问题所在。-prune不排除目录本身,而是排除目录内容,这意味着您将在排除目录的输出中得到不需要的行。
GetFree

95
好答案。我想补充一点,你可以通过改变第一排除在任何级别的目录.*。因此find -name "*.js" -not -path "*/omitme/*",无论深度如何,都将忽略名为“ omitme”的目录中的文件。
DeeDee

83
但是,它仍然遍历所有不需要的目录。我要添加我自己的答案。:-)
Daniel C. Sobral

18
但是请注意,仅当您不-print明确使用prune选项时,prune选项才起作用。
Daniel C. Sobral

39
最好说“这是使用-prune的替代方法”。提示-prune的答案显然不是错误的,它们不是您执行此操作的方式。
Jimbo

458

与其他提议的解决方案相比,我发现以下原因更容易推理:

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不排除的内容完全匹配。如果这句话使您感到困惑,则只需确保在整个命令中使用完整路径,如下所示:。如果您想更好地理解,请参见注释[1]。find /full/path/ -not \( -path /full/path/exclude/this -prune \) ...

\(和内部\)是一个完全 匹配的表达式build/external(请参见上面的重要说明),并且在成功时将避免遍历下面的任何内容。然后,将其作为带有转义括号的单个表达式分组,并以前缀作为前缀-notfind跳过该表达式匹配的任何内容。

有人可能会问,添加-not是否不会使所有其他文件都被隐藏起来-prune,答案是否定的。-prune起作用的方式是,一旦到达该目录下的文件,则该文件将被永久忽略。

这来自一个实际用例,在该用例中,我需要对Wintersmith生成的某些文件调用yui-compressor,但忽略了需要按原样发送的其他文件。


注意[1]:如果要排除/tmp/foo/bar并运行像这样的查找,find /tmp \(...则必须指定-path /tmp/foo/bar。另一方面,如果您运行这样的查找,cd /tmp; find . \(...则必须指定-path ./foo/bar


37
出色的答案,谢谢。这适用于多个排除项,并且可扩展(可读)。您是先生们,还是学者先生。感谢您提供多重排除的示例
-Freedom_Ben

7
:如果我想使用-删除开关这不起作用find . -not \( -path ./CVS -prune \) -type f -mtime +100 -delete find: The -delete action atomatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.
亚尼斯Elmeris

17
@Janis可以-exec rm -rf {} \;代替使用-delete
Daniel C. Sobral

11
通过检查的输出find,这确实很明显,但是它使我震惊。如果要在当前目录中搜索(通过指定.为搜索路径,或者根本不指定一个),则很可能希望在模式之后-path以开头./,例如:find -not \( -path ./.git -prune \) -type f
Zantier 2014年

7
此方法的更精确(且与POSIX兼容)的变体:find searchdir \! \( -type d \( -path './excludedir/*' -o -path './excludedir2/*' -o -path './excludedir3/*' \) -prune \)紧随其后的任何条件都应满足您的需求。
沃尔夫,

217

对于跳过目录的首选语法,这里显然存在一些困惑。

GNU意见

To ignore a directory and the files under it, use -prune

从GNU查找手册页

推理

-prune停止find下降到目录中。仅指定-not -path内容仍将进入已跳过的目录,但是-not -pathfind测试每个文件时将为false 。

问题 -prune

-prune 可以达到预期的目的,但是在使用时仍然需要注意一些事项。

  1. find 打印修剪后的目录。

    • TRUE这是预期的行为,它只是不落在其中。为避免完全打印目录,请使用在逻辑上将其省略的语法。
  2. -prune仅适用于-print其他操作。

    • 不正确-prune除了可以执行任何动作-delete为什么删除不起作用?为了-delete正常工作,查找需要按DFS顺序遍历目录,因为-delete将首先删除叶子,然后是叶子的父级,等等。但是为了明确起见-prunefind需要访问目录并停止降级,这显然,开启-depth或关闭都没有意义-delete

性能

我设置了三大顶尖upvoted答案的一个简单的测试,在这个问题上(替换-print-exec bash -c 'echo $0' {} \;展示另一个动作的例子)。结果如下

----------------------------------------------
# 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的语法丹尼尔C.索布拉尔的语法了10-25ms,以平均运行。GetFree的语法(不使用-prune)耗时865毫秒。因此,是的,这是一个非常极端的示例,但是如果您关心运行时并且正在做任何远程密集型工作,则应该使用-prune

注意Daniel C. Sobral的语法在两种-prune语法中表现更好。但是,我强烈怀疑这是某些高速缓存的结果,因为切换两者的运行顺序会导致相反的结果,而非修剪版本始终是最慢的。

测试脚本

#!/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

18
谢谢您的出色分析。关于“我强烈怀疑这是某些缓存的结果”,您可以运行以下命令:sudo sh -c“ free && sync && echo 3> / proc / sys / vm / drop_caches && free”清除缓存(请参见unix。 stackexchange.com/questions/87908/…)。
ndemou,2014年

经过对这两者的几次测试,-prune我可以知道几乎没有任何区别。请记住,哪个命令最先启动将受益于CPU性能,随后的CPU预热>性能下降会导致速度稍慢(我在@ndemou建议的情况下确实在每个命令之前清除了缓存)
Huy.PhamNhu

尝试name1() name2() name3()在上面的@BroSlow测试脚本中切换编号以更改执行顺序,以直观了解我所说的内容。在现实生活中,这两者之间并不明显。
Huy.PhamNhu

掌声。谢谢您的优质解答。
斯特凡

您不应该是-o,这意味着或。因此,您在第一步中进行修剪,然后在下一步中忽略所有相关内容。
mmm

94

这是唯一为我工作的人。

find / -name MyFile ! -path '*/Directory/*'

搜索除“目录”外的“ MyFile”。强调星星*。


13
此方法在macOS上有效,而接受的答案无效。我知道原始问题是针对Linux的。
Xavier Rubio Jansana '18

5
请注意,您可以! -path '*/Directory/*'连续向命令中添加多个命令以忽略多个目录
Aclwitt

可在MacOS上运行,但不能在Linux上运行...已确认
Marcello de Sales

docker container仅在与sh -c "find..."
Marcello de Sales

@Marcello de Sales当然,它可以在Linux上运行。
DimiDak

59

一种选择是使用grep排除所有包含目录名称的结果。例如:

find . -name '*.js' | grep -v excludeddir

44
这会使您的搜索非常缓慢
Dorian

6
此代码对我有用,其他代码(使用-prune)对我有用-无效。
安德隆

7
较大的结果会变慢,但在较小的集合中很有用。但是如何使用grep排除多个目录?当然是这样:find . -name '*.js' | grep -v excludeddir | grep -v excludedir2 | grep -v excludedir3但是可能会有某种grep方式。
TimoKähkönen'13年

6
如果要执行多次抓取,最好将其编写为正则表达式:egrep -v '(dir1|dir2|dir3)'。但是,在此特定案例研究中,最好将目录排除在find自身之内。
劳伦斯2014年

1
是的,您不需要括号,最好使用^以确保它与字符串开头的目录名匹配,例如:find。名称'* .js'| egrep -v“ ^ \ ./ excludeddir1 | ^ \ ./ excludeddir2”
Sofija 2015年

41

我更喜欢这种-not表示法……它更具可读性:

find . -name '*.js' -and -not -path directory

5
对不起,它不起作用。的手册页上find说:“要忽略目录及其下的文件,请使用-prune”。
ChristianDavén2012年

8
错了 它不会阻止find进入目录并遍历其中的所有文件。
GetFree 2013年

find . -iname '*' -and -not -path './somePath'不会阻止它进入所述目录。
Lemmings'13

这有助于我使用.git路径 find . -iname '*' -not -path './.git/*'
M.academy的Mark Shust在13年

7
@rane:更具体地说find . -not -path "*/.git*",就是您想要的。
2013年

20

使用-prune选项。因此,类似:

find . -type d -name proc -prune -o -name '*.js'

“ -d -name proc -prune”仅查找要排除的名为proc的目录。
“ -o”是“ OR”运算符。


1
这是唯一对我有用的“发现”解决方案。我希望排除的目录不在当前工作目录的正下方。
兰伯特

5
但是,添加-print到最后可能会改善结果。find . -type d -name .hg -prune -o -name data忽略(多个).hg目录的内容,但列出.hg目录本身。使用-print,它仅列出了我要查找的“数据”目录。
Lambart

19

-prune绝对有效,并且是最佳答案,因为它可以防止下降到您要排除的目录中。-not -path仍然会搜索排除的目录,只是不打印结果,如果排除的目录已装入网络卷或您没有权限,则可能会出现问题。

棘手的部分是,find参数的顺序非常特殊,因此,如果您输入的参数不正确,则命令可能无法正常工作。参数的顺序通常如下:

find {path} {options} {action}

{path}:将所有与路径相关的参数放在首位,例如 . -path './dir1' -prune -o

{options}-name, -iname, etc在该组中,最后一个选项是我获得最大的成功。例如-type f -iname '*.js'

{action}:您需要添加 -print使用时-prune

这是一个工作示例:

# setup test
mkdir dir1 dir2 dir3
touch dir1/file.txt; touch dir1/file.js
touch dir2/file.txt; touch dir2/file.js
touch dir3/file.txt; touch dir3/file.js

# search for *.js, exclude dir1
find . -path './dir1' -prune -o -type f -iname '*.js' -print

# search for *.js, exclude dir1 and dir2
find . \( -path './dir1' -o -path './dir2' \) -prune -o -type f -iname '*.js' -print

16

这是我用来排除某些路径的格式:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

我用它来查找不在“。*”路径中的所有文件:

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

我试过了,它仍然属于目录,因此速度肯定没有提高。
Br.Bill

10

-path -prune方法也可用于路径中的通配符。这是一条find语句,它将查找服务于多个git存储库的git服务器的目录,而忽略git内部目录:

find . -type d \
   -not \( -path */objects -prune \) \
   -not \( -path */branches -prune \) \
   -not \( -path */refs -prune \) \
   -not \( -path */logs -prune \) \
   -not \( -path */.git -prune \) \
   -not \( -path */info -prune \) \
   -not \( -path */hooks -prune \)  

9

要排除多个目录:

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)

要添加目录,请添加-o -path "./dirname/*"

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)

但是,如果要排除的目录很多,也许应该使用正则表达式


9

有很多不错的答案,我花了一些时间来了解命令的每个元素是什么以及其背后的逻辑。

find . -path ./misc -prune -o -name '*.txt' -print

find将开始在当前目录中查找文件和目录,因此find .

-o选项代表逻辑或,并将命令的两个部分分开:

[ -path ./misc -prune ] OR [ -name '*.txt' -print ]

不是 ./misc目录的任何目录或文件都不会通过第一次测试-path ./misc。但是它们将针对第二个表达式进行测试。如果名称与图案相对应,则*.txt可以选择打印-print

当find到达./misc目录时,该目录仅满足第一个表达式。因此,该-prune选项将应用于它。它告诉find命令不要浏览该目录。因此,。/ misc中的任何文件或目录都不会被find查找,也不会针对表达式的第二部分进行测试,也不会被打印。


每个人都有解决方案,但您的解释最好。我坚持要先使用-name而不是-path。您的解释足以得出我想要的。找 。-name“ * .txt” -print -o -path ./misc -prune
Vendetta V

7

对于可行的解决方案(已在Ubuntu 12.04(精确的穿山甲)上测试)...

find ! -path "dir1" -iname "*.mp3"

将在当前文件夹和子文件夹中搜索mp1文件,但在dir1子文件夹中除外。

采用:

find ! -path "dir1" ! -path "dir2" -iname "*.mp3"

...以排除dir1和dir2


对我不起作用。以上任何答案都没有。红帽。
塔帕

6

一个好的技巧,以避免打印修剪目录是使用-print(对于作品-exec的右侧后以及)-or之后-prune。例如, ...

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

将以扩展名.j2打印当前目录下所有文件的路径,并跳过所有隐藏目录。整洁。但如上所述,它还将打印正在跳过的每个目录的完整路径。以下不,...

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

因为从逻辑上讲-and,在-iname运算符之后和-print之前有一个隐藏的内容。-or由于操作的布尔顺序和关联性,这会将其绑定到子句的右侧。但是文档说,-print如果-print0未指定(或它的任何表亲... 等),则存在隐藏项。那么,为什么-or打印的左边没有显示呢?显然(并且,我第一次阅读手册页时并没有理解这一点),这是正确的,如果不存在-print -或-exec ANYWHERE,则在逻辑上撒满-print以便可以打印所有内容。如果连一个print-style操作在任何子句中表示,所有那些隐藏的逻辑操作都消失了,而您只能得到指定的内容。坦率地说,我可能反而更喜欢它,但是 afind仅使用描述性运算符显然不会执行任何操作,因此我认为这是合理的。如上所述,这一切也都适用-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个以上的答案并投票赞成,但有人可以希望。:-)


5

您可以使用prune选项来实现此目的。例如:

find ./ -path ./beta/* -prune -o -iname example.com -print

或反grep“ grep -v”选项:

find -iname example.com | grep -v beta

您可以在Linux find命令中找到详细说明和示例,这些命令从搜索中排除目录


grep解决方案是唯一一个排除所有具有相同名称的目录的解决方案。当尝试排除“ node_modules”时,这很有用。
bmacnaughton

3
@bmacnaughton-不正确!我来这里的目的是专门排除“ node_modules”,在阅读了许多我确定的好的答案后,find . -type f -print -o -path "*/node_modules" -prune使用通配符可以在任何级别上跳过“ node_modules”。-print在第一种选择上使用-type f -print只会打印该部分,因此不会列出“ node_modules”目录本身。(也可以颠倒:find . -path "*/node_modules" -prune -o -type f -print
斯蒂芬·P

* /在那里做什么。您要排除的确切文件是什么?ypu是否将其用作通配符?
Siju V '18

1
@StephenP,感谢您指出这一点;我学会了使用之间的区别./node_modules,并*/node_modules从它。就我而言,node_modules仅在我开始搜索的目录(以及该node_modules目录下)中存在,因此可以使用,find . -type f -print -o -path "./node_modules" -prune 因为node_modules在任何其他目录下都没有目录。
bmacnaughton

1
@SijuV-在我正在搜索的目录中有一个node_modules子目录,但是也有具有自己的node_modules./node_modules的子目录... using 仅匹配node_modules当前目录下的子目录.并修剪它;使用*/node_modulesmatchs并修剪任何深度的目录,因为*as glob匹配任何前导路径前缀,例如./test5/main/node_modules,不仅匹配./前缀。该*是通配符,但作为一个水珠而不是一个正则表达式。
斯蒂芬·P

5
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune

无法使这一工作。find ~/Projects -name '*.js' -\! -name 'node_modules' -prune仍在node_modules按其路径查找文件
mpen

1
@mpen,从stackoverflow.com/questions/4210042/…中,我了解到所需的语法是find ~/Projects -path ~/Projects/node_modules -prune -o -name '*.js' -print。该路径的名称必须与要打印目录时要查找的内容完全匹配。
PatS

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

似乎与

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

并且更容易记住IMO。


4

TLDR:使用-path <excluded_path> -prune -o选项了解您的根目录并从那里定制搜索。不要/在排除路径的末尾添加尾随。

例:

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print


为了有效地使用findI,我相信对文件系统目录结构有一个很好的了解。在我的家用计算机上,我具有多TB硬盘驱动器,其中大约一半的内容是使用rsnapshot(即rsync)备份的。尽管备份到物理上独立(重复)的驱动器,但它已安装在我的系统根目录(/)下/mnt/Backups/rsnapshot_backups/

/mnt/Backups/
└── rsnapshot_backups/
    ├── hourly.0/
    ├── hourly.1/
    ├── ...
    ├── daily.0/
    ├── daily.1/
    ├── ...
    ├── weekly.0/
    ├── weekly.1/
    ├── ...
    ├── monthly.0/
    ├── monthly.1/
    └── ...

/mnt/Backups/rsnapshot_backups/目录当前占用约2.9 TB的空间,其中包含约6000万个文件和文件夹。仅仅遍历这些内容需要花费时间:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find /mnt/Backups/rsnapshot_backups | wc -l
60314138    ## 60.3M files, folders
34:07.30    ## 34 min

time du /mnt/Backups/rsnapshot_backups -d 0
3112240160  /mnt/Backups/rsnapshot_backups    ## 3.1 TB
33:51.88    ## 34 min

time rsnapshot du    ## << more accurate re: rsnapshot footprint
2.9T    /mnt/Backups/rsnapshot_backups/hourly.0/
4.1G    /mnt/Backups/rsnapshot_backups/hourly.1/
...
4.7G    /mnt/Backups/rsnapshot_backups/weekly.3/
2.9T    total    ## 2.9 TB, per sudo rsnapshot du (more accurate)
2:34:54          ## 2 hr 35 min

因此,每当我需要在我的/(根)分区上搜索文件时,都需要处理(如果可能的话)遍历我的备份分区。


例子

在该线程中提出的各种建议中(如何在find。命令中排除目录)中,我发现使用公认的答案进行搜索的速度快得多,但有一些警告。

解决方案1

假设我要查找系统文件libname-server-2.a,但我不想搜索rsnapshot备份。要快速查找系统文件,请使用排除路径/mnt(即,使用/mnt,不是/mnt//mnt/Backups,或...):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
real    0m8.644s              ## 8.6 sec  <<< NOTE!
user    0m1.669s
 sys    0m2.466s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 3 sec     ## ~3 sec  <<< NOTE!

...只需几秒钟即可找到该文件,而这需要很多时间长(出现在所有的“排除”目录的递归):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print
find: warning: -path /mnt/ will not match anything because it ends with /.
/usr/lib/libname-server-2.a
real    33m10.658s            ## 33 min 11 sec (~231-663x slower!)
user    1m43.142s
 sys    2m22.666s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt/ -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 1775 sec    ## 29.6 min

解决方案2

此线程中提供的另一个解决方案(SO#4210042)的效果也很差:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -name "*libname-server-2.a*" -not -path "/mnt"
/usr/lib/libname-server-2.a
real    33m37.911s            ## 33 min 38 sec (~235x slower)
user    1m45.134s
 sys    2m31.846s

time find / -name "*libname-server-2.a*" -not -path "/mnt/*"
/usr/lib/libname-server-2.a
real    33m11.208s            ## 33 min 11 sec
user    1m22.185s
 sys    2m29.962s

总结 结论

使用“ 解决方案1 ”中说明的方法

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print

... -path <excluded_path> -prune -o ...

请注意,无论何时将尾随添加/到排除的路径中,该find命令都会递归地进入(所有这些)/mnt/*目录-在我的情况下,由于/mnt/Backups/rsnapshot_backups/*子目录的原因,该目录还包括约2.9 TB的文件搜索!通过不添加结尾/,搜索应几乎立即完成(几秒钟内)。

... -not -path <exclude path> ...同样,“解决方案2”()似乎可以在被排除的目录中进行递归搜索-不返回被排除的匹配项,但不必要地浪费了搜索时间。


在那些内搜索 rsnapshot备份中:

要在我的每小时/每天/每周/每月rsnapshot备份中找到一个文件):

$ START="$(date +"%s")" && find 2>/dev/null /mnt/Backups/rsnapshot_backups/daily.0 -name '*04t8ugijrlkj.jpg'; END="$(date +"%s")"; TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
find command took 312 sec   ## 5.2 minutes: despite apparent rsnapshot size
                            ## (~4 GB), it is in fact searching through ~2.9 TB)

排除嵌套目录:

在这里,我想排除嵌套目录,例如/mnt/Vancouver/projects/ie/claws/data/*,从中搜索时/mnt/Vancouver/projects/

$ time find . -iname '*test_file*'
./ie/claws/data/test_file
./ie/claws/test_file
0:01.97

$ time find . -path '*/data' -prune -o -iname '*test_file*' -print
./ie/claws/test_file
0:00.07

另外:-print在命令末尾添加将禁止打印排除目录:

$ find / -path /mnt -prune -o -name "*libname-server-2.a*"
/mnt
/usr/lib/libname-server-2.a

$ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a

不是文件的大小变慢find,而是它必须检查的目录条目数。因此,如果您拥有许多文件(特别是如果它们都是多重链接的话),则比只有几个千兆字节的文件要糟糕得多。
Toby Speight

@TobySpeight:好点。我提到搜索空间大小以指示比例,其中还包含许多文件。快速搜索根目录(/)sudo ls -R / | wc -l表示〜76.5M文件(除了“非配置”系统文件以外,大多数文件都已备份);/mnt/Vancouver/ls -R | wc -l表示〜2.35M文件; /home/victoria/包含0.668M个文件。
维多利亚·斯图尔特

4

您还可以使用正则表达式使用类似以下内容来包含/排除搜索的某些文件/目录:

find . -regextype posix-egrep -regex ".*\.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*" 

这只会给您所有js,vue,css等文件,但不包括node_modulesvendor文件夹中的所有文件。


3

我曾经find用来提供的文件列表xgettext,但想省略特定的目录及其内容。我尝试了许多-path组合的组合,-prune但无法完全排除我想消失的目录。

尽管我可以忽略要忽略的目录内容,但是find将目录本身作为结果之一返回,结果导致xgettext崩溃(不接受目录;仅接受文件)。

我的解决方案是简单地使用grep -v跳过结果中不需要的目录:

find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext

find我不能肯定地说,是否有这样的论点会100%奏效。grep头痛后使用,是一种快速简便的解决方案。


3

先前的答案在Ubuntu上都不好。尝试这个:

find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"

在这里找到这个


我看不出任何理由为何在Ubuntu上无法获得100分以上的答案。
Axel Beckert

嗯,让我们看看吗?也许是因为我尝试了所有这些?
sixro

在所有Linux发行版中,到处都可以找到相同的实现-GNU项目中的实现。唯一的区别可能是版本。但是,过去十年的变化并不那么具有侵入性,可能是为了权限匹配。
Axel Beckert

3

这在Mac上适合我:

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

搜索名称后缀为会排除vendorapp/cachedir php


最好在“ * .php”两边加上单引号,否则您将找不到所需的内容。
Br.Bill

3

对于那些无法使用-path-not的UNIX早期版本的用户

在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

可以传递的内容超过指定的目录。
MUY比利时

2

Laurence Gonsalves很好地回答了如何使用sh-find-sh中的修剪选项-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/多次,包裹find在一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

1
stackoverflow.com/questions/4210042/…中,我了解到,用于-pathmust 的语法必须与find的名称相匹配(如果要打印目录的话),例如 find . -path ./.git -prune -o -print,或者 find $HOME/foo -path $HOME/foo/.git -prune -o -print 有些答案只是说-path somedir不幸的是不够精确以至无用。
PatS

2

对于我所需要的,它的工作方式如下:landscape.jpg在所有服务器中从root开始查找,并排除/var目录中的搜索:

find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg

find / -maxdepth 1 -type d列出所有d在irectories/

grep -v /var 从列表中排除“ / var”

xargs -I '{}' find '{}' -name landscape.jpg执行任何命令,例如find使用列表中的每个目录/结果


请稍等,/尚未排除。您可能需要sed 1d
辛巴(Simba)

2

以下命令有效:

find . -path ./.git -prune -o -print

如果查找有问题,请使用该-D tree选项查看表达式分析信息。

find -D tree . -path ./.git -prune -o -print

-D all,以查看所有执行信息。

find -D all . -path ./.git -prune -o -print

1

我发现C源文件中的函数名称排除* .o和排除* .swp并排除(不是常规文件)并使用此命令排除dir输出:

find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach

1

execfor循环更好地使用动作:

find . -path "./dirtoexclude" -prune \
    -o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' \;

exec ... '{}' ... '{}' \;将一次每一个匹配的文件来执行,更换支架'{}'与当前文件名。

请注意,括号用单引号引起来,以防止其解释为shell脚本标点符号*


笔记

*find (GNU findutils) 4.4.2手册页的“示例”部分


1
很老的问题,但仍有改进的余地。我偶然发现它试图解决类似的问题,但没有一个答案令人满意。
艾伯托

exec经常使用该操作,发现它非常有用。{}如果文件路径中有空格,我通常会在之间加引号"{}"
Ludovic Kuty 2015年

@lkuty我本来要编辑我的帖子以反映您的评论,但是经过快速测试(不带引号,{}确实适用于名称中包含空格的文件)并查看了手册页,似乎仅需避免使用引号它们被误解为shell脚本标点符号。在这种情况下,您将使用单引号:'{}'
Alberto

我认为我必须用它来制作cpor mvrm。我会检查出来
朱利库季

1

我在上面尝试了命令,但是使用“ -prune”的命令都不适合我。最终我用下面的命令尝试了这个:

find . \( -name "*" \) -prune -a ! -name "directory"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.