前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux中find命令的使用详解(下)

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

作者头像
耕耘实录
发布2018-12-20 14:37:29
2.7K0
发布2018-12-20 14:37:29
举报
文章被收录于专栏:耕耘实录耕耘实录

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

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

四、ACTIONS

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

代码语言:javascript
复制
[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
...

上面的命令也相当于:

代码语言:javascript
复制
[root@GeekDevOps-find ~]# find / -name root -print >a.txt

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

代码语言:javascript
复制
[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语言中不一样,这一点学要我们特别注意一下。

代码语言:javascript
复制
[root@GeekDevOps-find ~]# find / -name b.txt -printf "%p"
/root/b.txt[root@GeekDevOps-find ~]#

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

代码语言:javascript
复制
[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找到的文件名。比如:

代码语言:javascript
复制
[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,是不是就有意义的多?比如:

代码语言:javascript
复制
[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

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

代码语言:javascript
复制
[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是包含匹配文件所在的子目录,而不是一个正常目录。

代码语言:javascript
复制
[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 {} + 我们还是先用例子来看一下这个格式和以分号结束的方式的差别:

代码语言:javascript
复制
[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指定的命令实际上只被执行了一次。这样用的限制也是不言而喻的:{}只能出现一次。

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

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

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

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

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

代码语言:javascript
复制
[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)实际上是用来连接多个表达式和确定其逻辑关系用的。

代码语言:javascript
复制
[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参数一样:

代码语言:javascript
复制
[root@GeekDevOps-find opt]# find / -name "Geek*" -a -type f

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

代码语言:javascript
复制
[root@GeekDevOps-find opt]# find / -name "Geek*" -o -type f

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

代码语言:javascript
复制
[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的手册。随时随地阅读我的文章,敬请关注同名微信公众号及头条号。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年01月25日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 四、ACTIONS
  • 五、操作符(OPERATORS)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档