从查找中排除目录。 命令

我试图为所有JavaScript文件运行查找命令,但是如何排除特定目录?

这是我们使用的查找代码。

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

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

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

这是一个多目录的例子:

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

在这里,我们排除了dir1,dir2和dir3,因为在findexpression式中它是一个动作,作用于条件-path dir1 -o -path dir2 -o -path dir3 (如果dir1或dir2或dir3),用type -d 。 进一步的行动是-o print ,只是打印。

如果-prune不适合你,这将会:

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

我发现以下比其他build议的解决scheme更容易推理:

 find build -not \( -path build/external -prune \) -name \*.js 

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

Inside \(\)是一个完全匹配build/external的expression式,并且在成功时避免遍历下面的任何东西 。 然后将这个分组作为一个带有转义括号的单个expression式,并以-not作为前缀,这将使find跳过与该expression式匹配的任何内容。

有人可能会问,如果添加-not不会使所有其他文件隐藏在-prune重新出现,答案是否定的。 -prune工作方式是,任何一旦达到目录下的文件都被永久忽略。

这也很容易扩大增加排除。 例如:

 find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js 

这里显然有一些混淆,那就是跳过目录的首选语法应该是什么。

GNU的意见

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

从GNU查找手册页

推理

-prune停止find从一个目录下降。 只要指定-not -path将仍然下降到跳过的目录中,但是不论何时findtesting每个文件,都不会使用-not -path

-prune问题

-prune做它的意图,但仍然有些事情,你必须照顾使用它。

  1. find打印修剪的目录。

    • TRUE这是预期的行为,它只是不下降。 要避免完全打印目录,请使用逻辑上省略的语法。
  2. -prune只能使用-print而不需要其他操作。

    • 不是真的 。 除了-delete之外, -prune可以使用任何操作。 为什么不使用删除? 对于删除工作,find需要以DFS顺序遍历目录,因为-delete将首先删除叶子,然后叶子的父母等…但是为了指定-prune有意义, find需要打到目录并停止降级,这显然与-depth-delete -depth

性能

我为这个问题设置了一个简单的testing(用-exec bash -c 'echo $0' {} \; -c'echo -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的语法在两个语法中执行得更好; 但是,我强烈怀疑这是一些caching的结果,因为切换两者的顺序导致相反的结果,而非修剪版本总是最慢的。

testing脚本

 #!/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=$((es)) 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=$((es)) 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=$((es)) printf " [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n" echo "Cleaning up test files..." cleanup 

一个选项是排除包含目录名称的所有结果与grep。 例如:

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

我更喜欢-not notation …它更可读:

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

使用-prune选项。 所以,像这样的:

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

'-type d -name proc -prune'只查找名为proc的目录以排除。
'-o'是一个'OR'运算符。

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

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

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

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

对于一个工作解决scheme(在Ubuntu 12.04(精确穿山甲)testing)…

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

将在当前文件夹和子文件夹中search除dir1子文件夹以外的MP3文件。

使用:

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

…排除dir1和dir2

要排除多个目录:

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

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

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

但是也许你应该使用正则expression式 ,如果有很多目录要排除。

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

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

或者反转grep“grep -v”选项:

 find -iname example.com | grep -v beta 

您可以在Linux中查找详细的说明和示例查找命令排除search目录

我正在使用find来提供xgettext的文件列表,并希望省略特定的目录及其内容。 我尝试了许多与-prune结合的-prune但无法完全排除我想要去的目录。

虽然我可以忽略我想要忽略的目录的内容 ,但find并返回目录本身作为结果之一,导致xgettext作为结果崩溃(不接受目录;只有文件)。

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

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

无论是否有一个可以100%发挥作用的论据,我都不能肯定地说。 使用grep是一些头痛之后的快速简单的解决scheme。

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

好像和你一样工作

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

而且更容易记住IMO。

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

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

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

我在这里find了

这适用于Mac上的我:

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

它将排除vendorapp/cache目录search名称后缀的php

-path -prune方法也适用于path中的通配符。 下面是一个查找语句,它将查找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 \) 

如何使用修剪selectfind在sh是劳伦斯贡萨尔斯如何-prune作品一个很好的答案。

这里是通用的解决scheme:

 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 

为了避免多次input/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 

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

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

for循环更好地使用exec操作:

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

exec ... '{}' ... '{}' \; 将为每个匹配文件执行一次,用当前文件名replace大括号'{}'

请注意,大括号括在单引号,以防止他们解释为shell脚本标点*


笔记

*find (GNU findutils) 4.4.2手册页的EXAMPLES部分

这是因为find 模式* foo * ”的文件:

 find ! -path "dir1" ! -path "dir2" -name "*foo*" 

但是如果你不使用模式findtesting文件),它就不起作用。 所以find不使用它以前评估过的“ 真实 ”和“ 虚假 ”的布尔。 以上表示法不工作用例示例:

 find ! -path "dir1" ! -path "dir2" -type f 

没有findtesting! 所以如果你需要find没有任何模式匹配的文件,使用-prune。 另外,通过使用剪枝find总是更快,而实际上跳过目录,而不是匹配它,或更好地不匹配它。 所以在这种情况下使用如下所示:

 find dir -not \( -path "dir1" -prune \) -not \( -path "dir2" -prune \) -type f 

要么:

 find dir -not \( -path "dir1" -o -path "dir2" -prune \) -type f 

问候

对于FreeBSD用户:

  find . -name '*.js' -not -path '*exclude/this/dir*' 

如果search目录有模式(在我的大多数情况下); 你可以简单地做如下:

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

在上面的例子中, 它search以“n”开始的所有子目录。

我发现了这个页面上的build议,很多其他页面在我的Mac OS X系统上不起作用。 但是,我find了一个适合我的变体。

最大的想法是searchMacintosh HD,但避免遍历所有外部卷,这些卷主要是时间机器备份,映像备份,装入共享和归档,但不必将其全部卸载,这通常是不切实际的。

这是我的工作脚本,我已经命名为“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$ 

各种path都与外部存档卷,Time Machine,虚拟机,其他挂载的服务器等有关。 一些卷名称中有空格。

一个好的testing运行是“findit index.php”,因为这个文件出现在我的系统的很多地方。 有了这个脚本,大约需要10分钟来search主硬盘。 没有这些排除,这需要很多小时。

我想知道目录的数量,文件MB 只是当前目录 – 而且这个代码正是我想要的:-)

来源

 - ... 2791037 Jun 2 2011 foo.jpg - ... 1284734651 Mär 10 16:16 foo.tar.gz - ... 0 Mär 10 15:28 foo.txt d ... 4096 Mär 3 17:12 HE d ... 4096 Mär 3 17:21 KU d ... 4096 Mär 3 17:17 LE d ... 0 Mär 3 17:14 NO d ... 0 Mär 3 17:15 SE d ... 0 Mär 3 17:13 SP d ... 0 Mär 3 17:14 TE d ... 0 Mär 3 19:20 UN 

代码

 format="%s%'12d\n" find . -type d -not -path "./*/*" | wc -l | awk -v fmt=$format '{printf fmt, " Anzahl Ordner = ", $1-1}' find . -type f -not -path "./*/*" | wc -l | awk -v fmt=$format '{printf fmt, " Anzahl Dateien = ", $1}' du . -hmS --max-depth=0 | awk -v fmt=$format '{printf fmt, " Groesse (MB) = ", $1}' 

注意: awk格式化数字需要额外的format="%s%'12d\n"

结果

 Anzahl Ordner = 8 Anzahl Dateien = 3 Groesse (MB) = 1.228 

不知道这是否会覆盖所有的边缘情况,但以下将是非常简单和直接的尝试:

ls -1|grep -v -e ddl -e docs| xargs rm -rf

这应该删除当前目录中的所有文件/目录excpet'ddls'和'docs'。

我尝试过上面的命令,但是没有一个使用“-prune”的人为我工作。 最终我用下面的命令试了一下:

 find . \( -name "*" \) -prune -a ! -name "directory"