Linux高级使用技巧:find命令的使用详解(下)

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

四、ACTIONS

这一部分的内容非常多,我就选取常用的部分进行学习、分享。ACTIONS也是表达式中的一部分,表达式中的actions类型参数主要是用来对找到的文件进行操作的参数。在上面的例子中,我们已经看到可以使用-ls参数对找到的文件进行长格式显示,这就是一个actions类型的参数。

-flsfile:跟-ls功能一样,区别是将信息写入file指定的文件,而不是显示在屏幕上。

-print:将找到的文件显示在屏幕上,实际上默认find命令就会将文件列印出来显示。

-print0:-print参数会将每个文件用换行分割,而这个参数适用null分割。有时候在脚本编程时可能会用上。

-fprintfile:-print参数的写入文件版本。将内容写到文件中,而不是显示在屏幕上。

-fprint0file:-print0的写入文件版本。

[root@GeekDevOps-find~]#find/-nameroot-fprinta.txt

[root@GeekDevOps-find~]#via.txt/dev/centos/root

/proc/1/task/1/root

/proc/1/root

上面的命令也相当于:

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

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

delete

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

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

/root/b.txt[root@GeekDevOps-find~]#

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

prune

以上例子中为了避免文件名shadow造成冲突,我在后面多加了一个w,注意区分。

-quit:找到符合条件的文件后立即退出,子进程同时也结束。

在find命令中,还可以直接执行一些命令,这个用得好的话也同样能起到事半功倍的效果。

-exec:find命令的exec是一个非常好用的参数,当然其可能造成的破坏也可能非常大。在使用之前千万要确定自己在做什么。

这个参数的常见格式是:-execcommand;

注意后面的分号。它是用来给find做标记用的。find在解析命令的时候,要区分给定的参数是要传给自己的还是要传给command命令的。所以find以分号作为要执行命令所有参数的结束标记。命令返回值为0则返回true。在exec参数指定的执行命令中,可以使用{}符号表示当前find找到的文件名。比如:

[root@GeekDevOps-find~]#find/etc/-name"passwd"-exececho{}\;

/etc/passwd

/etc/pam.d/passwd

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

exec

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

或者:

[root@GeekDevOps-find~]#find/-name"b.txt"-execcp{}{}.bak\;

这个命令可以将符合条件的文件都加个.bak后缀备份一份。于是我们可以执行删除了,删除前还是要确认清楚你要删的文件一定是对的。

-execdir:execdir和exec有一些差别,主要是在执行指定的命令时,exec是在find所指定的起始目录执行,而execdir是包含匹配文件所在的子目录,而不是一个正常目录。

exec与execdir

前一个命令列印出来的路径都是以/开头,后一个显示的都是当前目录下的某某文件。execdir的方式要比exec安全一些,因为这种执行方式避免了在解析文件名时所产生的竞争条件。

出了上述两种比较典型的执行命令的方法以外,find还对这两个参数提供了另一种形式的命令执行格式:

-execcommand{}+

-execdircommand{}+

我们还是先用例子来看一下这个格式和以分号结束的方式的差别:

[root@GeekDevOps-find~]#find/-namepasswd-execls{}+;

/etc/pam.d/passwd/etc/passwd/sys/fs/selinux/class/passwd/perms/passwd/usr/bin/passwd

/sys/fs/selinux/class/passwd:

indexperms

[root@GeekDevOps-find~]#find/-namepasswd-execdirls{}+;

indexperms

./passwd

./passwd

./passwd

./passwd

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

[root@GeekDevOps-find~]#find/-nameGeekDevOps.txt-execcp-t/opt/{}\+;

cp:不会以"/home/GeekDevOps/GeekDevOps.txt"覆盖刚创建的"/opt/GeekDevOps.txt"

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

[root@GeekDevOps-find~]#find/-nameGeekDevOps.txt-execcp{}/opt/\+;

find:遗漏「-exec」的参数

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

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

-ok

-okdir

它们的作用跟exec和execdir一样,区别只是在做任何操作之前,会让用户确认是不是ok?

[root@GeekDevOps-findopt]#pwd

/opt

[root@GeekDevOps-findopt]#ll

总用量0

[root@GeekDevOps-findopt]#find/-nameGeekDevOps.test-okcp-t/opt/{}\;

?y

?y

cp:"/opt/GeekDevOps.test"与"/opt/GeekDevOps.test"为同一文件

[root@GeekDevOps-findopt]#ll

总用量0

-rw-r--r--.1rootroot01月2511:23GeekDevOps.test

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

+的格式。

五、操作符(OPERATORS)

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

[root@GeekDevOps-findopt]#find/-name"Geek*"-typef

/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-findopt]#find/-name"Geek*"-a-typef

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

[root@GeekDevOps-findopt]#find/-name"Geek*"-o-typef

表示两个条件只要符合其中一个都可以。

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

[root@GeekDevOps-findopt]#find/\(-name"passwd"-a-typef\)-o\(-name"shadow"-a-typef\)/sys/fs/selinux/class/passwd/perms/passwd

/etc/passwd

/etc/shadow

/etc/pam.d/passwd

/usr/bin/passwd

这里表示的是:-name「passwd」-a-typef和-name「shadow」-a-typef是或关系。

find中还可能常用的其他参数比如:

-depth:制定了这个参数后,遇到目录先进入目录操作目录中的文件,最后再操作目录本身。

-maxdepth:目录最大深度限制。

-mindepth:目录最小深度限制。

至此,关于find命令的介绍基本完成了,这是一个比较常用的命令,还有更多的功能期待大家去发现,具体可以man一下find的手册。随时随地阅读我的文章,敬请关注同名微信公众号及CSDN博客。