我想找到以 _peaks.bed
结尾的文件,但要排除 tmp
和 scripts
文件夹中的文件。
我的命令如下:
find . -type f \( -name "*_peaks.bed" ! -name "*tmp*" ! -name "*scripts*" \)
但是它并没有起作用。在 tmp
和 script
文件夹中的文件仍然会被显示。
有人对此有什么想法吗?
以下是如何使用find
指定:
find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"
说明:
find .
- 从当前工作目录开始查找(默认情况下递归)-type f
- 指定只在结果中显示文件-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
考虑了整个路径 =)
使用
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"
下每个节点评估表达式。
find表达式只是条件评估。
\( \)
- 组操作(您可以使用-path "./tmp" -prune -o -path "./scripts" -prune -o
,但这更冗长)。-path "./script" -prune
- 如果-path
返回true并且是目录,则为该目录返回true,并且不要进入其中。-path "./script" ! -prune
- 它作为(-path "./script") AND (! -prune)
评估。它撤销了修剪的“始终为真”,使其始终为假。 它避免将"./script"
打印为匹配项。-path "./script" -prune -false
- 由于-prune
始终返回true,因此您可以在其后面跟随-false
执行与!
相同的操作。-o
- OR运算符。如果在两个表达式之间未指定运算符,则默认为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
返回真值,它将打印“./script”和“./tmp”。
在其他情况下,我们不需要使用-print
,因为我们将-prune
切换为始终返回false值。
提示:您可以使用 find -D opt expr 2>&1 1>/dev/null
来查看它是如何被优化和扩展的,
find -D search expr 2>&1 1>/dev/null
查看检查的路径。
find \( -path <path> -o -path <path> \) -prune -false -o -type f
在我的一边可以正常工作。如果我忘记在命令中加入 -
(例如输入 type f
而不是 -type f
),我会收到类似的错误消息。你尝试运行哪个命令? - f380cedric"./tmp"
和"/.scripts"
只有在当前目录的直接子目录下才能工作。使用"*/tmp"
和"*/scripts"
可以使它们在子目录中(递归)也能正常工作。 - M Imam Pratama\(-name tmp -or -name scripts\)
。 - Bobfind . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"
find ./ ! \( -path ./tmp -prune \) ! \( -path ./scripts -prune \) -type f -name '*_peaks.bed'
find ./\
-iname "some_arg" -type f\ # File(s) that you want to find at any hierarchical level.
! -iname "some_arg" -type f\ # File(s) NOT to be found on any hirearchic level (exclude).
! -path "./file_name"\ # File(s) NOT to be found at this hirearchic level (exclude).
! -path "./folder_name/*"\ # Folder(s) NOT to be found on this Hirearchic level (exclude).
-exec grep -IiFl 'text_content' -- {} \; # Text search in the content of the found file(s) being case insensitive ("-i") and excluding binaries ("-I").
例子
find ./\
-iname "*" -type f\
! -iname "*pyc" -type f\
! -path "./.gitignore"\
! -path "./build/*"\
! -path "./__pycache__/*"\
! -path "./.vscode/*"\
! -path "./.git/*"\
-exec grep -IiFl 'title="Brazil - Country of the Future",' -- {} \;
谢谢!
[参考文献:https://unix.stackexchange.com/q/73938/61742]
额外信息:
您可以将上述命令与您喜欢的编辑器一起使用,并分析找到的文件的内容,例如...
vim -p $(find ./\
-iname "*" -type f\
! -iname "*pyc" -type f\
! -path "./.gitignore"\
! -path "./build/*"\
! -path "./__pycache__/*"\
! -path "./.vscode/*"\
! -path "./.git/*"\
-exec grep -IiFl 'title="Brazil - Country of the Future",' -- {} \;)
对我而言,这个解决方案在使用 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
find . -path ./scripts -prune -name '*_peaks.bed' -type f
。不确定如何排除多个目录。即使指定了 type
,这也会列出顶级被排除的目录。除非你想要使用修剪来加速查找操作,否则通过 Grep 进行排除似乎更直接。 - Mohnish尝试类似这样的东西
find . \( -type f -name \*_peaks.bed -print \) -or \( -type d -and \( -name tmp -or -name scripts \) -and -prune \)
如果目标是执行(而不是打印),只需在原地替换即可,如果我有点错误,请不要太惊讶。
find
中的许多扩展,但由于问题标记为Linux,所以这不是一个问题。好答案。 - Jonathan Leffler$ ! -path "./directory/*"
- Thomas Bennett-prune
而不是检查树中的每个文件。”如果您要排除的目录层级很深,或者包含大量文件并且您关心性能,则应改用-prune
选项。 - thdoan