详解shell脚本(五)——玩转find查找

find查找

#find命令有一个选项-iname会忽略字母的大小写
find . \( -name "*.txt" -o -name "*.pdf" \) -print
#\(以及\)会让中间的内容视为一个整体 -o 匹配多个条件中的一个
find . ! -name "*.txt" -print #否定参数"!"
  • 基于目录深度的搜索

find命令在使用时会遍历所有的子目录。我们可以采用深度选项-maxdepth和 -mindepth来限制find命令遍历的目录深度。使用下列命令将find命令向下的最大深度限制为1:find . -maxdepth 1 -name “f*” -print 打印出深度距离当前目录至少两个子目录的所有文件:

find . -mindepth 2 -name “f*” -print

  • 根据文件类型 -type
    普通文件 f 符号链接 l目录 d 字符设备 c 块设备 b 套接字 s FIFO p
  • 根据时间
    访问时间(-atime)修改时间(-mtime)内容修改 变化时间(-ctime)权限改变

单位是天,-表示小于,+表示大于

find . type -f -atime -7 -print #最近7天被访问的
find . type -f -atime 7 -print #7天前访问的文件
find . type -f -atime +7 -print #访问时间超过7天
#单位是分钟的 amin mmin cmin 
  • 根据文件大小 -size
    b块512字节c字节 w字 2字节 k 1024字节 M 1024K G 1024M
  • 删除匹配的文件 -delete

find . -type f -name “*.swp” -delete

  • 基于文件权限和所有权的匹配

find . -type f -perm 664 -print 打印权限是644的文件

-user USER 找到某个特定用户所拥有的文件

  • 利用find执行命令或动作 -exec

    find . -type -user root -exec chown slynux {} \;

在这个命令中, {}是一个与 -exec选项搭配使用的特殊字符串。对于每一个匹配的文件,{}会被替换成相应的文件名。例如, find命令找到两个文件test1.txt和test2.txt,其所有者均为slynux,那么find就会执行:chown slynux {}

有时候我们并不希望对每个文件都执行一次命令。我们更希望使用文件列表作为命令参数,这样就可以少运行几次命令了。如果是这样,可以在exec中使用+来代替;。

$ find . -type f -name “*.c” -exec cat {} \;>all_c_files.txt

将给定目录中的所有C程序文件拼接起来写入单个文件all_c_files.txt

我们无法在-exec参数中直接使用多个命令。它只能够接受单个命令,不过我们可以耍一个小花招。把多个命令写到一个shell脚本中(例如command.sh),然后在-exec中使用这个脚本

  • 让find跳过特定的目录

    find devel/source_path ( -name “.git” -prune ) -o ( -type f -print ) #Instead of ( -type -print ),而是选择需要的过滤器

以上命令打印出不包括在.git目录中的所有文件的名称(路径)

玩转xargs

我们可以用管道将一个命令的stdout(标准输出)重定向到另一个命令的stdin(标准输入)。例如:

cat foo.txt | grep “test”

但是,有些命令只能以命令行参数的形式接受数据,而无法通过stdin接受数据流。在这种情况下,我们没法用管道来提供那些只有通过命令行参数才能提供的数据。

xargs命令应该紧跟在管道操作符之后,以标准输入作为主要的源数据流。它使用stdin并通过提供命令行参数来执行其他命令。

xargs命令把从stdin接收到的数据重新格式化,再将其作为参数提供给其他命令xargs可以作为一种替代,其作用类似于find命令中的 -exec。

xargs有一个选项-I,可以提供上面这种形式的命令执行序列。我们可以用-I指定替换字符串,这个字符串在xargs扩展时会被替换掉。如果将-I与xargs结合使用,对于每一个参数,命令都会被执行一次。

cat args.txt | xargs -I {} ./cecho.sh -p {} -1
-p arg1 -1 #
-p arg2 -1 #
-p arg3 -1 #
#-I {}指定了替换字符串。对于每一个命令参数,字符串{}都会被从stdin读取到的参数替换掉。

正则表达式-regex

E-mail地址通常采用name@host.root这种形式,所以可以将其一般化为[a-z0-9]+@[a-z0-9]+.[a-z0-9]+。符号+ 指明在它之前的字符类中的字符可以出现一次或多次。

find . -type f -user root -exec chown slynux {} \;

在这个命令中,{}是一个与 -exec选项搭配使用的特殊字符串。对于每一个匹配的文件,{}会被替换成相应的文件名。

find . -type f -name "*.c" -exec cat {} \;>all_c_files.txt
#执行脚本
-exec ./commands.sh {} \;

find devel/source_path  \( -name ".git" -prune \) -o \( -type f -print \)
# Instead of \( -type -print \),而是选择需要的过滤器

( -name “.git” -prune )的作用是用于进行排除,它指明了 .git目录应该被排除在外,而( -type f -print )指明了需要执行的动作。这些动作需要被放置在第二个语句块中(打印出所有文件的名称和路径)。

#! /bin/bash
#文件名:cecho.sh
echo $*'#'

cat args.txt | xargs -I {} ./cecho.sh -p {} -l
-p arg1 -l #
-p arg2 -l #
-p arg3 -l #

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

find source_code_dir_path f -name "*.c" -print0 | xargs -0 wc -l
#-0 将\0作为输入定界符 

结合stdin,巧妙运用while语句和子shell

xargs只能以有限的几种方式来提供参数,而且它也不能为多组命令提供参数。要执行包含来自标准输入的多个参数的命令,有一种非常灵活的方法。包含while循环的子shell可以用来读取参数,然后通过一种巧妙的方式执行命令

cat files.txt | (while read arg; do cat $arg; done )
#等同于 cat files.txt | xargs -I {} cat {}

用tr进行转换

tr只能通过stdin(标准输入),而无法通过命令行参数来接受输入。它的调用格式如下: tr [options] set1 set2

如果两个字符集的长度不相等,那么set2会不断重复其最后一个字符,直到长度与set1相同。如果set2的长度大于set1,那么在set2中超出set1长度的那部分字符则全部被忽略。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值