find命令,由不能打印‘afile’总结到的

shouhua_57

Michael

Posted on May 28, 2024

find命令,由不能打印‘afile’总结到的

关于

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.
Enter fullscreen mode Exit fullscreen mode

就是说find . -name afile -o -name bfile -print命令即使afile存在也不会打印出来,这就很奇怪了,读起来是afile或者bfile就print,看起来很直观,但是不是这么判断的,下面我们总结下manpage和常见用法习惯。

用法

find [OPTIONS] [starting-point] [EXPRESSION]
Enter fullscreen mode Exit fullscreen mode
  • OPTIONS 里面 -H -L -P 用于表示如何处理symbolic link; -O 表示优化级别,一般用不到; -D 用于调试,比如
`-D help` 打印出所有调试选项
`-D tree` 打印出predicate list,可以看到默认添加的参数等,非常有用
Enter fullscreen mode Exit fullscreen mode
  • starting-point 可以有多个,最好使用相对路径和绝对路径,比如./abc/abc, 避免被乱解释了,比如路径开头为-,就会被解释为expression argument。
  • EXPREESION 用于表示怎么匹配文件和匹配后怎么做。包括以下几个部分: Tests, Actions, Global options, Positional options, Operators

    1. Tests 返回true或者false。根据文件属性包括日期、权限、状态、大小等,选择我们关心部分作为测试参数,比如-empty表示文件内容为空的判断
    2. Actions 返回true或者false。 匹配文件怎么做,比如,-print将当前匹配文件名打印
    3. Global Options 总是返回true。 影响所有的tests和actions参数,比如, -depth指示find按照深度优先方式traverse
    4. Positional Options 总是返回true。 只是影响他之后的tests和actions参数,比如,-regextype 指示他后面使用的regex方言类型
    5. 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: {}' \; \) \)     
    

注意点

  1. 默认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]  )
    
  2. 如果只有-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

  3. 以下actions会禁止-print, 包括-delete, -exec, -execdir, -ok, -okdir, -fls, -fprint, -fprintf, -ls, -print, -printf

  4. -maxdepth 0 (global options)可以指示只处理start point

  5. 为了防止被当成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每次执行命令都会询问。

  6. -exec COMMAND [\;|\+]
    最后;+, 前者是每次都执行一次COMMAND, 后者是将参数以空格形式分割,最后执行一次COMMAND。

  7. -name pattern
    表示file的basename是否符合pattern, 比较时候会去掉leading directory

  8. -path pattern
    匹配的是整个filename, 包括路径, 比如

     find . \( ! -path './node_modules/*' ! -name 'eslint.config.js' -type f \) -print
    
  9. -print0

    主要是防止文件名含有特殊字符,比如\n, space等,批处理时会被转译截断,所以使用\0结尾,跟xargs -0配对使用

答案

-a优先级比-o高,另外-name afile不会添加-print, 所以即使匹配到了还是会无声的过了,最后只是打印了bfile, 如果存在的话。

💖 💪 🙅 🚩
shouhua_57
Michael

Posted on May 28, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related