Michael
Posted on May 28, 2024
关于
find命令是常用到的,读到manpage里面一段话不是很明白,于是整个manpage读了一遍终于整明白了。
Please note that -a when specified implicitly (for example by two
tests appearing without an explicit operator between them) or
explicitly has higher precedence than -o. This means that `find .
-name afile -o -name bfile -print` will never print afile.
就是说find . -name afile -o -name bfile -print
命令即使afile存在也不会打印出来,这就很奇怪了,读起来是afile或者bfile就print,看起来很直观,但是不是这么判断的,下面我们总结下manpage和常见用法习惯。
用法
find [OPTIONS] [starting-point] [EXPRESSION]
- OPTIONS 里面
-H -L -P
用于表示如何处理symbolic link;-O
表示优化级别,一般用不到;-D
用于调试,比如
`-D help` 打印出所有调试选项
`-D tree` 打印出predicate list,可以看到默认添加的参数等,非常有用
- starting-point 可以有多个,最好使用相对路径和绝对路径,比如
./abc
和/abc
, 避免被乱解释了,比如路径开头为-
,就会被解释为expression argument。 -
EXPREESION
用于表示怎么匹配文件和匹配后怎么做。包括以下几个部分:Tests
,Actions
,Global options
,Positional options
,Operators
。-
Tests
返回true
或者false
。根据文件属性包括日期、权限、状态、大小等,选择我们关心部分作为测试参数,比如-empty
表示文件内容为空的判断 -
Actions
返回true
或者false
。 匹配文件怎么做,比如,-print
将当前匹配文件名打印 -
Global Options
总是返回true
。 影响所有的tests和actions参数,比如,-depth
指示find按照深度优先方式traverse -
Positional Options
总是返回true
。 只是影响他之后的tests和actions参数,比如,-regextype
指示他后面使用的regex方言类型 -
Operators
逻辑连接参数,如果expr之间没有逻辑连接默认是-a
表示and。 而且不管显式或者隐式-a
优先级都高于-o
,其他有趣的还包括()
调整precedence! expr
或者(-not expr)
取反expr1, expr2
2个表达式都会执行,但是结果取expr2的, 举例
find . ! -path './node_modules/*' \( \( -type f -print \) , \( -type d -exec echo 'directory: {}' \; \) \)
-
注意点
-
默认action是
-print
, 这里的默认是说,如果命令中没有任何一个action, 会在最后添加-a -print
, 但是如果有多个判断分支,但一个有action, 那不会添加默认,比如
find . -name afile -o -name bfile -print
这个afile判断是不会添加
-print
的,由于-a
优先级高于-o
, 所以最后变成了
find . ( -name afile ) -o ( -name bfile -a -print )
其中默认添加了
-a
, 遇到afile时候就会跳过了,相当于continue, 可以使用-D tree
看到最后执行的命令表达式
find -D tree . -name afile -o -name bfile -print
会得到:
Optimized Command Line: -name afile [est success rate 0.1] -o [est success rate 0.2] ( -name bfile [est success rate 0.1] -a [est success rate 0.1] -print [est success rate 1] )
如果只有
-prune
或者-quit
,还是会添加默认-print
。
-prune
表示如果是文件夹,不递归他。-prune
总是返回true, 常用于跳过某个文件或者目录,比如find . -path './node_modules' -prune -o -type f -print
;
-quit
用于成功了整个命令退出,比如打印第一个匹配成功的文件find . -path './node_moduels' -prune -o -type f -print -quit
。以下actions会禁止
-print
, 包括-delete, -exec, -execdir, -ok, -okdir, -fls, -fprint, -fprintf, -ls, -print, -printf
。-maxdepth 0
(global options)可以指示只处理start point为了防止被当成SHELL中特殊字符,find命令中参数有些要注意转译,比如括号、分号、加号等,凡是在SHELL中特殊字符尽量转移,不然后果未知, 比如
find . -path './node_modules' -prune -o -type f -exec echo {} ;
如果最后的;
不转译,find命令找不到结束符号报错。还有最后的+
也是一样,find . -path './node_modules' -prune -o -type f -ok echo {} \;
,-ok
每次执行命令都会询问。-exec COMMAND [\;|\+]
最后;
和+
, 前者是每次都执行一次COMMAND, 后者是将参数以空格形式分割,最后执行一次COMMAND。-name pattern
表示file的basename是否符合pattern, 比较时候会去掉leading directory-
-path pattern
匹配的是整个filename, 包括路径, 比如
find . \( ! -path './node_modules/*' ! -name 'eslint.config.js' -type f \) -print
-print0
主要是防止文件名含有特殊字符,比如\n
,space
等,批处理时会被转译截断,所以使用\0
结尾,跟xargs -0
配对使用
答案
-a
优先级比-o
高,另外-name afile
不会添加-print
, 所以即使匹配到了还是会无声的过了,最后只是打印了bfile, 如果存在的话。
Posted on May 28, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.