Linux中find命令的使用详解(下)

版权声明:本文为耕耘实录原创文章,各大自媒体平台同步更新。欢迎转载,转载请注明出处,谢谢

通过前两篇文章,如果我们都掌握了的话,在平常的系统运维、管理中基本可以达到得心应手的程度了。接下来,我们通过这篇文章,我们将更加深入了解关于find命令的高级应用。接下来我们将分为三个部分分别进行介绍。

四、ACTIONS

这一部分的内容非常多,我就选取常用的部分进行学习、分享。ACTIONS也是表达式中的一部分,表达式中的actions类型参数主要是用来对找到的文件进行操作的参数。在上面的例子中,我们已经看到可以使用-ls参数对找到的文件进行长格式显示,这就是一个actions类型的参数。 -fls file:跟-ls功能一样,区别是将信息写入file指定的文件,而不是显示在屏幕上。 -print:将找到的文件显示在屏幕上,实际上默认find命令就会将文件打印出来显示。 -print0:-print参数会将每个文件用换行分割,而这个参数适用null分割。有时候在脚本编程时可能会用上。 -fprint file:-print参数的写入文件版本。将内容写到文件中,而不是显示在屏幕上。 -fprint0 file:-print0的写入文件版本。

[root@GeekDevOps-find ~]# find / -name root -fprint a.txt
[root@GeekDevOps-find ~]# vi a.txt 
/dev/centos/root
/proc/1/task/1/root
/proc/1/root
...

上面的命令也相当于:

[root@GeekDevOps-find ~]# find / -name root -print >a.txt

-delete:可以将找到的文件直接删除。

[root@GeekDevOps-find ~]# ll
总用量 8
-rw-------. 1 root root 1605 1月   7 18:38 anaconda-ks.cfg
-rw-r--r--. 1 root root   44 1月   7 23:12 a.sh
-rw-r--r--. 1 root root    0 1月  24 23:32 a.txt
-rw-r--r--. 1 root root    0 1月   7 23:11 b.txt
-rw-r--r--. 1 root root    0 1月   7 23:12 c.txt
[root@GeekDevOps-find ~]# find / -name a.txt
/root/a.txt
[root@GeekDevOps-find ~]# find / -name a.txt -delete
[root@GeekDevOps-find ~]# ls
anaconda-ks.cfg  a.sh  b.txt  c.txt

-printf:格式化输出方式打印,这个就很类似于C语言的printf函数了,在这里可以参考C语言的这个函数,通过man find,我发现,基本就是C语言中printf函数的兄弟。不过写法有点与C语言中不一样,这一点学要我们特别注意一下。

[root@GeekDevOps-find ~]# find / -name b.txt -printf "%p"
/root/b.txt[root@GeekDevOps-find ~]#

-prune:如果复合条件的是一个目录,则不进入目录进行查找。

[root@GeekDevOps-find ~]# mkdir /etc/shadoww
[root@GeekDevOps-find ~]# touch /etc/shadoww/shadoww
[root@GeekDevOps-find ~]# mkdir -p /etc/GeekDevOps/shadoww
[root@GeekDevOps-find ~]# find / -name shadoww -prune
/etc/shadoww
/etc/GeekDevOps/shadoww
[root@GeekDevOps-find ~]# find / -name shadoww 
/etc/shadoww
/etc/shadoww/shadoww
/etc/GeekDevOps/shadoww

以上例子中为了避免文件名shadow造成冲突,我在后面多加了一个w,注意区分。 -quit:找到符合条件的文件后立即退出,子进程同时也结束。 在find命令中,还可以直接执行一些命令,这个用得好的话也同样能起到事半功倍的效果。 -exec:find命令的exec是一个非常好用的参数,当然其可能造成的破坏也可能非常大。在使用之前千万要确定自己在做什么。 这个参数的常见格式是:-exec command ; 注意后面的分号。它是用来给find做标记用的。find在解析命令的时候,要区分给定的参数是要传给自己的还是要传给command命令的。所以find以分号作为要执行命令所有参数的结束标记。命令返回值为0则返回true。在exec参数指定的执行命令中,可以使用{}符号表示当前find找到的文件名。比如:

[root@GeekDevOps-find ~]# find /etc/ -name "passwd" -exec echo {} \;
/etc/passwd
/etc/pam.d/passwd

上面的命令表示,找到/etc/目录下文件名为passwd的文件,并echo其文件名。注意再使用分号的时候前面要加转义字符\,因为分号也是bash的特殊字符,所以bash会先解释它。前面加上\就可以让bash直接将其传给find命令,这个分号由find解释,而不是bash。其实这个exec用的比较废话,毕竟find本身就会找到相关条件的文件并显示其文件名。但是试想如果我们将echo换成rm或者cp,是不是就有意义的多?比如:

[root@GeekDevOps-find ~]# ll
总用量 8
-rw-------. 1 root root 1605 1月   7 18:38 anaconda-ks.cfg
-rw-r--r--. 1 root root   44 1月   7 23:12 a.sh
-rw-r--r--. 1 root root    0 1月   7 23:11 b.txt
-rw-r--r--. 1 root root    0 1月   7 23:12 c.txt
[root@GeekDevOps-find ~]# find / -name "c.txt" -exec rm {} \;
[root@GeekDevOps-find ~]# ll
总用量 8
-rw-------. 1 root root 1605 1月   7 18:38 anaconda-ks.cfg
-rw-r--r--. 1 root root   44 1月   7 23:12 a.sh
-rw-r--r--. 1 root root    0 1月   7 23:11 b.txt

效果是不是非常明显?请不要轻易执行这个命令!! 或者:

[root@GeekDevOps-find ~]#  find / -name "b.txt" -exec cp {} {}.bak \;
[root@GeekDevOps-find ~]# ll
总用量 8
-rw-------. 1 root root 1605 1月   7 18:38 anaconda-ks.cfg
-rw-r--r--. 1 root root   44 1月   7 23:12 a.sh
-rw-r--r--. 1 root root    0 1月   7 23:11 b.txt
-rw-r--r--. 1 root root    0 1月  25 00:29 b.txt.bak

这个命令可以将符合条件的文件都加个.bak后缀备份一份。于是我们可以执行删除了,删除前还是要确认清楚你要删的文件一定是对的。 -execdir:execdir和exec有一些差别,主要是在执行指定的命令时,exec是在find所指定的起始目录执行,而execdir是包含匹配文件所在的子目录,而不是一个正常目录。

[root@GeekDevOps-find ~]# find / -name passwd -exec ls {} \;
index  perms
/sys/fs/selinux/class/passwd/perms/passwd
/etc/passwd
/etc/pam.d/passwd
/usr/bin/passwd
[root@GeekDevOps-find ~]# find / -name passwd -execdir ls {} \;
index  perms
./passwd
./passwd
./passwd
./passwd

前一个命令打印出来的路径都是以/开头,后一个显示的都是当前目录下的某某文件。execdir的方式要比exec安全一些,因为这种执行方式避免了在解析文件名时所产生的竞争条件。 出了上述两种比较典型的执行命令的方法以外,find还对这两个参数提供了另一种形式的命令执行格式: -exec command {} + -execdir command {} + 我们还是先用例子来看一下这个格式和以分号结束的方式的差别:

[root@GeekDevOps-find ~]# find / -name passwd -exec ls {} +;
/etc/pam.d/passwd  /etc/passwd  /sys/fs/selinux/class/passwd/perms/passwd  /usr/bin/passwd
/sys/fs/selinux/class/passwd:
index  perms
[root@GeekDevOps-find ~]# find / -name passwd -execdir ls {} +;
index  perms
./passwd
./passwd
./passwd
./passwd

其实就是说,对于command {} ;格式来说,每找到一个文件就执行一遍相关命令,而command {} +格式的意思是说,先执行find,找到所有符合条件的文件之后,将每个文件作为命令的一个参数传给命令执行,exec指定的命令实际上只被执行了一次。这样用的限制也是不言而喻的:{}只能出现一次。

[root@GeekDevOps-find ~]# find / -name GeekDevOps.txt -exec cp -t /opt/ {} \+ ;
cp: 不会以"/home/GeekDevOps/GeekDevOps.txt" 覆盖刚创建的"/opt/GeekDevOps.txt"

上面这个命令将符合条件的文件全部cp到了/opt/目录中,当然如果文件有重名的情况下,会被覆盖掉。从这个命令中我们学习一下{} +格式的使用注意事项,它不能写成:

[root@GeekDevOps-find ~]# find / -name GeekDevOps.txt -exec cp {} /opt/ \+;
find: 遗漏“-exec”的参数

所以只能使用-t参数改变cp命令的参数顺序来指定相关的动作。

我们不难看出,直接使用exec和execdir是很危险的,因为他们会直接对找到的文件调用相关命令,并且没有任何确认。所以我们不得不在进行相关操作前再三确认,以防止误操作。当然,find命令也给了更安全的exec参数,它们就是: -ok -okdir 它们的作用跟exec和execdir一样,区别只是在做任何操作之前,会让用户确认是不是ok?

[root@GeekDevOps-find opt]# pwd
/opt
[root@GeekDevOps-find opt]# ll
总用量 0
[root@GeekDevOps-find opt]# find / -name GeekDevOps.test -ok cp -t /opt/ {} \;
< cp ... /root/GeekDevOps.test > ? y
< cp ... /opt/GeekDevOps.test > ? y
cp: "/opt/GeekDevOps.test" 与"/opt/GeekDevOps.test" 为同一文件
[root@GeekDevOps-find opt]# ll
总用量 0
-rw-r--r--. 1 root root 0 1月  25 11:23 GeekDevOps.test

通过上面的例子,我们发现GeekDevOps.test这个文件被复制了2次,并且最后一行还有提示,这是由于我们查找和复制都在同一个目录下面,在find命令查找到这个文件时,进行复制,接着进行下一次查找,结果就查找到了之前复制过来的文件,这一点在平时的使用中我们需要注意一下。每一次cp你都要确认是不是要这么做。只要你输入的是y或者以y开头的任何字符串,都是确认。其他的字符串是否认。另外,这两个参数不支持{} +的格式。

五、操作符(OPERATORS)

find的操作符(OPERATORS)实际上是用来连接多个表达式和确定其逻辑关系用的。

[root@GeekDevOps-find opt]# find / -name "Geek*" -type f
/root/GeekDevOps.txt
/root/GeekDevOps.doc
/root/GeekDevOps.docx
/root/GeekDevOps.wps
/root/GeekDevOps.txt.bak
/root/GeekDevOps.test
/var/spool/mail/GeekDevOps
/home/GeekDevOps/GeekDevOps.doc
/home/GeekDevOps/GeekDevOps.txt
/home/GeekDevOps/GeekDevOps.pdf
/home/GeekDevOps/GeekDevOps.bpm
/home/GeekDevOps/GeekDevOps.wps
/opt/GeekDevOps.test

这个find命令中使用了两个表达式,他们之间没有任何分隔,这是实际上表达的含义是,找到两个条件都符合的文件。实际上就是表达式的逻辑与关系,这跟-a参数连接或者-and参数一样:

[root@GeekDevOps-find opt]# find / -name "Geek*" -a -type f

除了逻辑与关系以外,还有逻辑或关系:

[root@GeekDevOps-find opt]# find / -name "Geek*" -o -type f

表示两个条件只要符合其中一个都可以。 在条件表达式前面加!表示对表达式取非。同样的也可以用-not参数。另外如果表达式很多,可以使用( expr )确定优先级。

[root@GeekDevOps-find opt]# find / \( -name "passwd" -a -type f \) -o \( -name "shadow" -a -type f \)
/sys/fs/selinux/class/passwd/perms/passwd
/etc/passwd
/etc/shadow
/etc/pam.d/passwd
/usr/bin/passwd

这里表示的是:-name “passwd” -a -type f和-name “shadow” -a -type f是或关系。 find中还可能常用的其他参数比如: -depth:制定了这个参数后,遇到目录先进入目录操作目录中的文件,最后再操作目录本身。 -maxdepth:目录最大深度限制。 -mindepth:目录最小深度限制。 至此,关于find命令的介绍基本完成了,这是一个比较常用的命令,还有更多的功能期待大家去发现,具体可以man一下find的手册。随时随地阅读我的文章,敬请关注同名微信公众号及头条号。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏jerryteng的专栏

学习Go语言-组织源码文件

46890
来自专栏BY的专栏

终端显示树状文件结构

39580
来自专栏Python小屋

Python批量提取PDF文件中的文本

首先需要执行命令pip install pdfminer3k来安装处理PDF文件的扩展库。 import os import sys import time p...

37550
来自专栏Youngxj

emlog让微语支持html代码

35240
来自专栏架构师之路

30秒懂SQL中的join(2幅图+30秒)

废话不多说,直接上图秒懂。 t1表的结构与数据如下: ? t2表的结构与数据如下: ? inner join select * from t1 inner j...

30470
来自专栏大内老A

学习ASP.NET Core, 怎能不了解请求处理管道[5]: 中间件注册可以除了可以使用Startup之外,还可以选择StartupFilter

中间件的注册除了可以借助Startup对象(DelegateStartup或者ConventionBasedStartup)来完成之外,也可以利用另一个叫做St...

34870
来自专栏Laoqi's Linux运维专列

shell 1>&2 2>&1 &>filename重定向的含义和区别

14850
来自专栏php

Composer常见错误解决

执行composer install遇到错误:Your requirements could not be resolved to an installable...

33200
来自专栏PHP在线

拒绝重复造轮子,用composer搞自己的框架(2)

久负盛名的 CodeIgniter 框架是很多人的 PHP 开发入门框架,同样也是我开始学习如何从头构建一个网站的框架。在 CI中我学到了很多,其中对 MVC ...

38790
来自专栏zhangdd.com

tomcat8 启动报错: ignoring option PermSize=256m处理方法

Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=512m; suppor...

18710

扫码关注云+社区

领取腾讯云代金券