使用find命令,但排除两个目录中的文件


86

我想找到以结尾的文件_peaks.bed,但排除tmpscripts文件夹中的文件。

我的命令是这样的:

 find . -type f \( -name "*_peaks.bed" ! -name "*tmp*" ! -name "*scripts*" \)

但这没有用。中的文件tmpscript文件夹仍将显示。

有人对此有想法吗?

Answers:


189

您可以通过以下方法指定find

find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"

说明:

  • find . -从当前工作目录开始查找(默认为递归)
  • -type f-指定find仅在结果中包含文件
  • -name "*_peaks.bed" -查找名称以结尾的文件 _peaks.bed
  • ! -path "./tmp/*" -排除路径以开头的所有结果 ./tmp/
  • ! -path "./scripts/*" -还排除路径以开头的所有结果 ./scripts/

测试解决方案:

$ mkdir a b c d e
$ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
$ find . -type f ! -path "./a/*" ! -path "./b/*"

./d/4
./c/3
./e/a
./e/b
./e/5

您非常接近,该-name选项仅考虑基本名称,其中-path考虑了整个路径=)


辛苦了 但是,您忘记了OP想要的事情之一,而找不到以结尾的文件_peaks.bed
亚历克斯

2
这在GNU中使用了许多扩展名find,但是由于问题被标记为Linux,所以这不是问题。好答案。
乔纳森·莱夫勒

1
简短说明:如果.在初始查找提示时使用,则必须在排除的每个路径中使用它。路径匹配非常严格,不会进行模糊搜索。因此,如果您使用find / -type f -name *.bed" ! -path "./tmp/"它不起作用。你需要! -path "/tmp"让它快乐。
Peelman

3
重要的是要注意,*很重要。$ ! -path "./directory/*"
Thomas Bennett 2014年

3
根据手册页:“要忽略整个目录树,请使用-prune而不是检查树中的每个文件。” 如果排除的目录运行得很深或有大量文件,并且您在乎性能,请改用该-prune选项。
thdoan '17

8

这是您可以做到的一种方法...

find . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"

2
这具有与任何版本的findGNU一起使用的优点,而不仅仅是与GNU一起使用find。但是,该问题被标记为Linux,因此并不重要。
乔纳森·莱夫勒

2

使用

find \( -path "./tmp" -o -path "./scripts" \) -prune -o  -name "*_peaks.bed" -print

要么

find \( -path "./tmp" -o -path "./scripts" \) -prune -false -o  -name "*_peaks.bed"

要么

find \( -path "./tmp" -path "./scripts" \) ! -prune -o  -name "*_peaks.bed"

顺序很重要。从左到右评估。始终从路径排除开始。

说明

不要使用-not(或!)排除整个目录。使用-prune。如手册中所述:

−prune    The primary shall always evaluate as  true;  it
          shall  cause  find  not  to descend the current
          pathname if it is a directory.  If  the  −depth
          primary  is specified, the −prune primary shall
          have no effect.

并在GNU中找到手册:

-path pattern
              [...]
              To ignore  a  whole
              directory  tree,  use  -prune rather than checking
              every file in the tree.

的确,如果您使用-not -path "./pathname",find将评估下的每个节点的表达式"./pathname"

查找表达式只是条件评估。

  • \( \)-分组操作(可以使用-path "./tmp" -prune -o -path "./scripts" -prune -o,但是更详细)。
  • -path "./script" -prune-如果-path返回true,并且是一个目录,返回该目录真实,也没有落在其中。
  • -path "./script" ! -prune-评估为(-path "./script") AND (! -prune)。它将修剪的“始终为真”恢复为始终为假。避免将打印"./script"作为匹配项。
  • -path "./script" -prune -false-由于-prune始终返回true,因此您可以遵循-false来做比!
  • -o-或运算符。如果在两个表达式之间未指定运算符,则默认为AND运算符。

因此,\( -path "./tmp" -o -path "./scripts" \) -prune -o -name "*_peaks.bed" -print扩展为:

[ (-path "./tmp" OR -path "./script") AND -prune ] OR ( -name "*_peaks.bed" AND print )

打印在这里很重要,因为如果不打印,它会扩展为:

{ [ (-path "./tmp" OR -path "./script" )  AND -prune ]  OR (-name "*_peaks.bed" ) } AND print

-print由find添加-这就是为什么大多数时候不需要在表达式中添加它的原因。并且由于-prune返回true,因此它将打印“ ./script”和“ ./tmp”。

在其他情况下则没有必要,因为我们切换-prune为始终返回false。

提示:您可以find -D opt expr 2>&1 1>/dev/null用来查看它是如何优化和扩展的,
find -D search expr 2>&1 1>/dev/null以查看检查了哪个路径。


0

尝试类似

find . \( -type f -name \*_peaks.bed -print \) -or \( -type d -and \( -name tmp -or -name scripts \) -and -prune \)

如果我弄错了也不要太惊讶。如果目标是执行者(而不是打印对象),只需将其替换在适当位置即可。


0

对我而言,此解决方案不适用于使用find命令执行的命令,不知道为什么,所以我的解决方案是

find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

说明:与sampson-chen一号相同,但增加了

-prune-忽略...的处理路径

-o-如果没有匹配项,则打印结果,(修剪目录并打印其余结果)

18:12 $ mkdir a b c d e
18:13 $ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
18:13 $ find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

gzip: . is a directory -- ignored
gzip: ./a is a directory -- ignored
gzip: ./b is a directory -- ignored
gzip: ./c is a directory -- ignored
./c/3:    0.0% -- replaced with ./c/3.gz
gzip: ./d is a directory -- ignored
./d/4:    0.0% -- replaced with ./d/4.gz
gzip: ./e is a directory -- ignored
./e/5:    0.0% -- replaced with ./e/5.gz
./e/a:    0.0% -- replaced with ./e/a.gz
./e/b:    0.0% -- replaced with ./e/b.gz

接受的答案不起作用,但这可行。使用prune 、find . -path ./scripts -prune -name '*_peaks.bed' -type f。不知道如何排除多个目录。即使type已指定,它也会列出顶级排除目录。除非您想使用prune加快查找操作,否则通过Grep进行排除似乎更简单。
Mohnish

我也很难排除多个目录,但是上面的注释给了我一个有效的答案。我使用了多个'-not -path'实例,并且在每个路径表达式中都包含了第一个参数中使用的完整前缀,以'find'并以星号结尾(并转义任何点)。
jetset

0

您可以尝试以下操作:

find ./ ! \( -path ./tmp -prune \) ! \( -path ./scripts -prune \) -type f -name '*_peaks.bed'

2
关于这样一个古老的问题(4年!),您想解释一下为什么这个新答案更好或更不同,而不仅仅是“转储”代码。
Nic3500 '17
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.