find命令的exec选项以及xargs命令

自己的《Linux系统管理初学者指南--基于CentOS 7.6》已于2019年10月份出版,对于这本书的质量总体上感觉还算满意,但是限于当时的知识水平,有些地方描述的仍然不是很清楚,所以在讲课的过程中也在不断进行修订。比如最近在讲到find命令的exec选项时,不少学生就提出疑问,因而我对原书中这部分内容进行了重写,希望再版时可以订正。
find命令的exec选项以及xargs命令

“-exec”选项,把查找到的结果当作文件进行处理

“-exec”选项后面要跟上进一步处理所要执行的命令,在命令中可以使用“{}”表示find命令查找到的结果,而且最后必须添加“ \;”表示命令结束(注意前面有个空格)。
例如,找出/tmp目录中所有后缀为“.txt”的文件并将其删除。
[root@localhost ~]# find /tmp -name "*.txt" -exec rm -f {} \;
很多同学在这里会疑惑,为什么这里用管道符“|”(将在2.9.5节介绍)无法实现上面的操作呢?比如我们做下面的测试:

[root@localhost ~]# touch /tmp/{a,b,c}.txt  #在/tmp目录中生成3个测试文件
[root@localhost ~]# find /tmp -name "*.txt" | rm -f     #利用管道结合rm删除
[root@localhost ~]# find /tmp -name "*.txt"     #测试文件仍然存在
/tmp/a.txt
/tmp/b.txt
/tmp/c.txt
[root@localhost ~]# find /tmp -name "*.txt" -exec rm -f {} \;   #利用exec结合rm删除
[root@localhost ~]# find /tmp -name "*.txt" #测试文件被成功删除

exec选项最主要的作用就是可以将find命令找到的结果当成文件去处理,而默认情况下,find命令找到的结果是被当作文本信息去处理的。
怎样理解上面这段话呢?比如对于执行“find /tmp -name "*.txt"”命令所找到的三个文件:/tmp/a.txt、/tmp/b.txt、/tmp/c.txt,默认情况下find命令只是把符合查找条件的这三个文件找到,并把它们的名字在屏幕上输出,因而我们在屏幕上所看到的只是三行文本信息。对于文本信息,可以使用之前介绍的文件内容操作命令进行处理,比如用wc命令统计行数,用grep命令进行过滤等。

[root@localhost ~]# find /tmp -name "*.txt" | wc -l     #统计find找到的文件数量
3
[root@localhost ~]# find /tmp -name "*.txt" | grep 'a'  #对find的结果进行过滤
/tmp/a.txt

对于文本信息,之前介绍的文件和目录操作命令就无法处理了,比如cp、mv、rm等,因为这些命令所操作的对象必须是文件。此时exec选项就可以派上用场,因为它的主要作用就是可以将find命令找到的结果不再看作是文本信息,而是看作文件。因而如果需要对find的结果用文件操作命令进行进一步处理的话,那么就需要结合exec选项。
例如,查找/boot目录下的以“init”开头的文件,并将其复制到/tmp目录。
[root@localhost ~]# find /boot -name "init*" -exec cp {} /tmp \;
例如,在/etc目录中查找大小在1MB以上的文件,并人性化显示其详细信息。

[root@localhost ~]# find /etc -size +1M -exec ls -lh {} \;
……
-r--r--r--. 1 root root 7.6M 9月   5 18:53 /etc/udev/hwdb.bin
-rw-r--r--. 1 root root 1.4M 4月  11 09:32 /etc/brltty/zh-tw.ctb

xargs命令

当在find命令中利用-exec选项对查找到的结果进行进一步处理时,有时可能会出现问题。这是因为-exec是将find所找到的结果一次性地送给后面的命令进行处理,有时候find可能会找到大量的文件,超出了后面的命令所能处理的参数范围,这时就会出现溢出错误,错误信息通常是“参数列太长”或“参数列溢出”,这时就可以使用xargs命令。xargs虽然本身是一个独立的Linux命令,但通常都是被用来配合find命令使用。通过xargs,可以将find所找到的结果分批次地送给之后的命令进行处理,从而避免出现溢出问题。
xargs命令需要通过管道与find命令配合使用,xargs的命令格式“find ……| xargs commands”。
下面我们先准备一个测试文件。

[root@localhost ~]# mkdir /tmp/pass
[root@localhost ~]# echo "password:123" >> /tmp/pass/test.txt

假设在/tmp目录中存放了大量的文件,在其中的某个文件里存放了一个密码,关键字为“password”,我们现在希望能够将这个存放了密码的文件找出来。
如果利用find命令的-exec选项,可以执行下面的命令:

[root@localhost ~]# find /tmp -type f -exec grep "password" {} \;
password:123

可以发现,虽然通过上面的命令找出了密码,但并没有显示存放该密码的文件名。下面换做用xargs命令来实现该要求,xargs就可以将关键字所在的文件一并显示出来。

[root@localhost ~]# find /tmp -type f | xargs grep "password"
/tmp/pass/test.txt:password:123

再比如,我们希望将/tmp目录以及/tmp所有下级子目录中,文件名以“.txt”作为后缀的文件都复制到/root目录中。如果用find命令的-exec选项来实现:
[root@localhost ~]# find /tmp -name "*.txt" -exec cp {} /root \;
如果用xargs命令来实现,同样需要用“{}”来代指find命令查找到的结果,并且需要为xargs命令添加-i选项。
[root@localhost ~]# find /tmp -name "*.txt" | xargs -i cp {} /root
通过这几个实例可以发现,xargs命令与find命令-exec选项的功能基本相同,所以如果-exec选项可以满足要求,那么就无需使用xargs命令。xargs命令的主要用途在于它可以对find命令找到的结果分批处理,避免出现溢出错误。
比如在/etc目录中一共有2507个普通文件。

[root@localhost ~]# find /etc -type f | wc -l
2507

如果我们希望能找出/etc目录中所有包含关键字“PermitRootLogin”的文件,分别用这两种方法来实现:

[root@localhost ~]# find /etc -type f -exec grep "PermitRootLogin" {} \;
#PermitRootLogin yes
# the setting of "PermitRootLogin without-password".
[root@localhost ~]# find /etc -type f | xargs grep "PermitRootLogin" 
/etc/ssh/sshd_config:#PermitRootLogin yes
/etc/ssh/sshd_config:# the setting of "PermitRootLogin without-password".

可以发现在用-exec选项的方法实现时,出现了明显的卡顿,如果数据量再大一些的话,可能就会导致溢出。而用xargs命令来实现,一方面更为快速,另一方面不会出现溢出问题,而且显示的内容也更为详细。所以在进行这类操作时,更加推荐使用xargs命令。

猜你喜欢

转载自blog.51cto.com/yttitan/2455746
今日推荐