blog:shell:06_shell_command_find

Shell find命令

find [starting-point...] [expression]

从starting-point指定的目录开始查找, 例如: find ./ -print

从当前目录开始查找,并打印目录和文件列表 -print 打印出匹配文件的文件名, 并使用 \n 作为分隔文件的定界符。 -print0 使用\0作为分隔文件的定界符。

-name

      指定了文件名必须匹配的字符串,可以使用通配符, 例如 ".txt"表示匹配所有以 .txt结尾的文件名
      例: `find ./ -name "*.txt" -print`
      

-iname

      与-name类似,只不过在匹配名字的时候会忽略大小写.
      

操作符

      `\(expr\)`  括号需要使用反斜杠转义
      `! expr`    对expr取反,表示否定
      `expr1 -a expr2`    两个表达式相与
      `expr1 -o expr2`    两个表达式相或
      例如: `find ./ \( -name "*.txt" -o -name "*.pdf" \) -print`

-regex

      基于正则表达式来匹配文件.
      例如: 查找当前目录下所有的pdf或者txt文件
            `find ./ -regex ".*\(\.pdf\|\.sh\)$"`
            

指定目录深度

      find默认会遍历所有的子目录, -maxdepth设置最大深度, -mindepth指定最小深度,表示从指定的深度开始向下查找.
      例: `find ./ -mindepth 2 -type 2 -print`
      注意: -maxdepth或-mindepth应该作为靠前的参数出现,不然可能会影响find的效率 
              例如例如 -maxdepth 在 -type 参数之后, 那么find将先找出所有符合type的文件,然后筛选指定的深度范围.
              

-type

      指定文件类型
      

Unix/Linux文件系统中的每个文件都有3种时间戳(timestamp) 访问时间(-atime): 用户最近一次访问该文件的时间 修改时间(-mtime): 文件内容最后一次被修改的时间 变化时间(-ctime): 文件元数据(metadata,例如权限或者所有权)最后一次被修改的时间

-atime -mtime -ctime 可以作为find的选项,其后跟整数值,单位是天. 这些整数值还可以带上+或者-, +表示大于,-表示小于

例如:

1. 查找最近7天被访问过的文件
find ./ -type f -atime -7
2. 查找恰好在7天前被访问过的文件
find ./ -type f -atime 7
3. 查找访问时间超过7天的所有文件
find ./ -type f -atime +7

类似地,也可以使用-mtime -ctime进行查找

以分钟为计量单位的选项: -amin -mmin -cmin

-newer

  查找比指定文件更新的文件(修改时间大于指定文件)
  例: 查找比file.txt修改时间更长的文件
  `find ./ -type f -newer file.txt -print`

-size

1. 查找大于2k的文件
    find . -type f -size +2k
2. 查找小于2k的文件
    find . -type f -size -2k
3. 查找等于2k的文件
    find . -type f -size 2k

除了k之外,还可以使用其他的单位 b block(1个block可能等于512Byte或者4k)

      查看block size的大小, 例如: `sudo tune2fs -l /dev/sda11 | grep Block`

c byte w word, word=2 bytes k 1024 bytes M 1024 KB G 1024 MB

-delete

      删除匹配到的文件
      例: 删除当前目录下所有的.swp文件
      `find ./ -type f -name "*.swp" -delete`
  

执行命令 -exec command ;

      find解析所有的参数,直到遇到 `;` 结束, 分号需要转义.
      例: 查找user为root的文件,并使用chown改变owner为slynux
      `find ./ -type f -user root -exec chown slynux {} \;`
      其中`{}` 是一个特殊的字符串,与-exec一起使用。对于每一个匹配的文件, `{}`被替换为相应的文件名
      
      例: 将修改时间超过10天的jpg文件移动到OLD_DIR目录中
      `find . -type f -mtime +10 -name "*.jpg" -exec cp {} OLD_DIR/ \;`

-prune就像一个判断语句, 当prune前面的表达式匹配的时候,prune就会输出true。 如果-prune后面跟的是-o选项,表示如果prune前面的选项成立,就不会执行-o后面的内容了; 如果prune前面的条件不成立,那么将打印输出。

跳过特定的目录 例如: 搜索时,跳过所有的.git目录

find . \( -name ".git" -prune \) -o \( -type f -print \)

xargs

我们可以用管道将一个命令的stdout重定向到另一个命令的stdin, 例如: cat foo.txt | grep "test" 但是有些命令只能以命令行参数的形式接收数据,而无法通过stdin接收数据, 在这种情况下,就不能通过管道为后续命令提供参数

xargs对从标准输入接收到的数据重新格式化,再将其作为参数提供给其他命令。默认使用空格或者换行符作为分隔参数来处理标准输入. 如果没有指定command, 那么默认的command是echo, xargs可作为find命令中-exec的一种替代方式.

OPTIONS:

  1. 0, –null
用字符串结束符替代空格分隔输入参数. 引号和反斜杠都看做字面意思,不表示特殊含义.
当输入参数中含有空格,引号,换行符的时候这个参数比较有用,与find的-print0的效果差不多.

-d delim, –delimiter=delim

  指定输入参数的分隔符,分隔符只能是单个字符,转义字符

例:

$ echo "splitXsqlitXsqlitXsqlit" | xargs -d X
split sqlit sqlit sqlit

同时结合-n,可以将输入划分为多行 例:

$ echo "splitXsqlitXsqlitXsqlit" | xargs -d X -n 2
split sqlit
sqlit sqlit

构造参数列表:

假如command的命令格式为: command -p arg1 -l 由于输入参数中arg1是唯一可变的文本, xargs有一个-I选项,可以构造上述形式的参数列表 -I 可以指定一个替换字符串,这个字符串在xargs扩展时会被替换掉。

例:

echo "*.txt" | xargs -I {} find ./ -maxdepth 1 -type f -name "{}"

-I{} 指定了替换字符串, xargs会将从stdin中接收到的参数替换掉命令序列中的{}

使用-I的时候,命令似乎是在一个循环中执行一样, 如果有n个参数,那么命令就会连同{}一起被执行n次, 而{}在每次执行中都会被替换为对应的参数。
args.txt中的内容如下:
$ cat args.txt 
*.txt
*.pdf

$ cat args.txt | xargs -I {} find ./ -maxdepth 1 -type f -name "{}"
./example.txt
./args.txt
./english_17.2.pdf

find命令会循环2次, {}会分别被替换为 *.txt 和 *.pdf

如果给xargs加上-t选项,就可以看到xargs每次执行命令的详细过程:
$ cat args.txt | xargs -t -I {} find ./ -maxdepth 1 -type f -name "{}"
find ./ -maxdepth 1 -type f -name *.txt 
./example.txt
./args.txt
find ./ -maxdepth 1 -type f -name *.pdf 
./english_17.2.pdf

xargs与find结合很方便,但人们通常以一种错误的方式使用他们。例如:

find . -type f -name "*.txt" -print | xargs rm -f

这样做很危险,有时可能会删除不必要的文件。 我们不能确定find命令输出结果的delimiter是'\n'还是' '。 很多文件名中都可能会包含空格符。而xargs很可能会误认为他们是delimiter,例如hell text.txt常被xargs误认为是hell和text.txt

只要我们把find的输出作为xargs的输入,就必须将-print0与find结合使用,以null来分隔输出。例如:

find . -type f -name "*.txt" -print0 | xargs -0 rm -f

find的选项-print表示输出结果是以'\n'分隔的, -print0的输出是以'\0'分隔的 xargs -0  将\0作为输入定界符.

例: 统计源码目录中所有C程序文件的行数

find sourcecodedir_path -type f -name “*.c” -print0 | xargs -0 wc -l

  • blog/shell/06_shell_command_find.txt
  • 最后更改: 2022/01/09 17:31
  • 127.0.0.1