“ 本文正在参加「金石计划 . 瓜分6万现金大奖」 ”
8.3.6 find:查找目录下的文件
8.3.6.1 命令详解
【命令星级】 ★★★★★
【功能说明】
find命令用于查找目录下的文件,同时还可以调用其他命令执行相应的操作。
【语法格式】
find [-H] [-L] [-P] [-D debugopts] [-Olevel] [pathname] [expression]
find [选项] [路径] [操作语句]
说明:
注意子模块的先后顺序。
图8-3为find命令语法的使用说明。
图8-3 find命令语法的使用说明
【选项说明】
表8-9针对find命令的参数选项进行了说明。
表8-9 find命令的参数选项及说明
8.3.6.2 使用范例
8.3.6.2.1 基础范例
范例8-10: 查找指定时间内修改过的文件。
[root@centos7 ~]# find . -atime -2 #“.”代表当前目录,查找2天内被访问的文件使用选项atime,-2代表两天内。
.
./.bash_logout
./.bash_profile
./.bashrc
./.bash_history
./.lesshst
./test
./test/dir5
./test/dir5/sub1
./test/dir5/sub1/test
./test/dir5/dir2
./test/dir5/dir2/dir1
./test/dir5/dir2/dir1/sub1
./test/dir5/dir2/dir1/sub1/test
./test/dir5/dir3
./test/neteagle
./hello.txt
./test.txt
./test1.txt
./test3.txt
./opt_sysctl.sh
./exportfs_usage.sh
./menu.sh
./test2.txt
./neteagle.txt
./.viminfo
./neteagle2.txt
./a.txt
./b.txt
./neteagle
./neteagle/neteagle.jpg
./neteagle/arp.zip
./neteagle/test.doc
./neteagle/neteagle.ppt
./neteagle/xiaodong
./netealge_link.txt
./neteagle20201010
[root@centos7 ~]# find /data/ -mtime -5 #使用绝对路径/data/,查找修改时间在5天以内的文件使用mtime。
/data/
/data/neteagle.txt
/data/neteagle2.txt
/data/test.txt
find查找时间的说明如图8-4所示。
图8-4 find查找时间的说明示意图
具体说明如下。
-
-4:表示文件更改时间距现在4天以内。
-
+4:表示文件更改时间距现在4天以前。
-
4:表示距现在第4天。
范例8-11: 用-name指定关键字查找。
[root@centos7 ~]# find /var/log -mtime +5 -name '*.log' #在/var/log/目录下查找5天前以“*.log”结尾的文件。 /var/log/anaconda/anaconda.log /var/log/anaconda/X.log /var/log/anaconda/program.log /var/log/anaconda/packaging.log /var/log/anaconda/storage.log /var/log/anaconda/ifcfg.log /var/log/anaconda/ks-script-O7AZwN.log /var/log/anaconda/journal.log范例8-12: 利用“!”反向查找。
[root@centos7 ~]# find . -type d #-type表示按类型查找,d代表目录,查找当前目录下的所有目录。 . ./test ./test/dir5 ./test/dir5/sub1 ./test/dir5/sub1/test ./test/dir5/dir2 ./test/dir5/dir2/dir1 ./test/dir5/dir2/dir1/sub1 ./test/dir5/dir2/dir1/sub1/test ./test/dir5/dir3 ./neteagle ./neteagle/xiaodong [root@centos7 ~]# find . ! -type d #!表示取反,查找不是目录的文件,注意感叹号的位置。 ./.bash_logout ./.bash_profile ./.bashrc ./.cshrc ./.tcshrc ./anaconda-ks.cfg ./.bash_history ./.lesshst ./test/.file4.txt ./test/dir5/file1.txt ./test/dir5/file2.txt ./test/dir5/file6.txt ./test/neteagle ./hello.txt ./test.txt ./test1.txt ./test3.txt ./opt_sysctl.sh ./exportfs_usage.sh ./menu.sh ./test2.txt ./neteagle.txt ./.viminfo ./neteagle2.txt ./a.txt ./b.txt ./neteagle/neteagle.jpg ./neteagle/arp.zip ./neteagle/test.doc ./neteagle/neteagle.ppt ./netealge_link.txt ./neteagle20201010范例8-13: 按照目录或文件的权限来查找文件。
[root@centos7 ~]# find /data/ -perm 755 #按照文件权限查找文件,755是权限的数字表示方式。 /data/范例8-14: 按大小查找文件。
[root@centos7 ~]# find . -size +1000c #查找当前目录下文件大小大于1000字节的文件。 . ./anaconda-ks.cfg ./.bash_history ./.viminfo范例8-15: 查找文件时希望忽略某个目录。
[root@centos7 ~]# mkdir -p /data/dir{1..3} [root@centos7 ~]# find /data -path "/data/dir3" -prune -o -print #参数-path用于指定路径样式,配合-prune参数用于排除指定目录。 /data /data/neteagle.txt /data/neteagle2.txt /data/test.txt /data/dir1 /data/dir2代码中的-path "/data/dir3" -prune -o -print是-path "/data/dir3" -a -prune -o -print的简写。其中,-a和-o类似于Shell中的"&&"和"||",当-path "/data/dir3为真时,执行-prune;为假时,执行-print。
范例8-16: 忽略多个目录。
[root@centos7 ~]# find /data ( -path /data/dir2 -o -path /data/dir3 ) -prune -o -print /data /data/neteagle.txt /data/neteagle2.txt /data/test.txt /data/dir1使用圆括号可以将多个表达式结合在一起,但是圆括号在命令行中另有特殊含义,所以此处使用“\”进行转义,即告诉bash不对后面的字符“()”作解析,而是留给find命令处理。而在"( -path"中左括号和-path之间有空格,就是“(空格-path”,"dir3 )"中dir3和)右括号之间有空格,就是“dir3空格)”,这是语法要求。
范例8-17: 使用user和nouser选项。
[root@centos7 ~]# touch file2.txt [root@centos7 ~]# chown nobody:nobody file2.txt #chown命令用于改变文件的用户和用户组,具体用法见chown命令的讲解。 [root@centos7 ~]# ll -h file2.txt -rw-r--r--. 1 nobody nobody 0 Oct 10 20:34 file2.txt [root@centos7 ~]# find . -user nobody #查看用户为nobody的文件。 ./file2.txt [root@centos7 ~]# chown 555 file2.txt [root@centos7 ~]# ll -h file2.txt -rw-r--r--. 1 555 nobody 0 Oct 10 20:34 file2.txt #如果这种数字的属主就需要使用-nouser参数了。 [root@centos7 ~]# find . -nouser #查找没有对应任何用户的文件。 ./file2.txt这个例子是为了查找那些属主账户已经被删除的文件,使用-nouser选项时,不必给出用户名。
范例8-18: 使用group和nogroup选项。
[root@centos7 ~]# find . -group nobody #这个功能与上一个例子类似,此处是查找用户组为nobody的文件。 ./file2.txt [root@centos7 ~]# chown .555 file2.txt [root@centos7 ~]# find . -nogroup #查找没有对应任何用户组的文件。 ./file2.txt范例8-19: 查找比某个文件新或旧的文件。
如果希望查找更改时间比,某个文件(file1)新,但比另一个文件(file2)旧的所有文件,可以使用-newer选项。它的一般形式为:-newer file1 ! -newer file2。其中,“!”是逻辑非符合,即取反的意思。
[root@centos7 /data]# find . -newer neteagle.txt #在当前目录查找时间比neteagle.txt新的文件。 . ./neteagle2.txt ./test.txt ./dir1 ./dir2 ./dir3 ./file2.txt [root@centos7 /data]# find . -newer neteagle.txt ! -newer file2.txt #查找更改时间比neteagle.txt新但比file2.txt旧的文件。 ./neteagle2.txt ./test.txt ./dir1 ./dir2 ./dir3 ./file2.txt #包含file2.txt。范例8-20: 逻辑操作符的使用。
[root@centos7 /data]# mkdir test [root@centos7 /data]# mkdir xingfujie [root@centos7 /data]# mkdir a [root@centos7 /data]# mkdir ext [root@centos7 /data]# mkdir xiaodong [root@centos7 /data]# mkdir xiaofen [root@centos7 /data]# find . -maxdepth 1 -type d . #-maxdepth 1查找一级目录,类似于tree -L 1。 ./dir1 ./dir2 ./dir3 ./test ./xingfujie ./a ./ext ./xiaodong [root@centos7 /data]# find . -maxdepth 1 -type d ! -name "." #使用感叹号“!”取反,输出名字为点的行。 ./dir1 ./dir2 ./dir3 ./test ./xingfujie ./a ./ext ./xiaodong ./xiaofen [root@centos7 /data]# find . -maxdepth 1 -type d ! -name "." -o -name "neteagle" #-o表示或的意思,显示除“.”以外的所有目录或文件名为neteagle的文件。 ./dir1 ./dir2 ./dir3 ./test ./xingfujie ./a ./ext ./xiaodong ./xiaofen [root@centos7 /data]# find . -maxdepth 1 -type d ! -name "." -a -name "ext" #-a在这里是并且的意思,查找不为点号并且名字为ext的目录,最后的结果只显示名为ext的目录。 ./ext范例8-21: find正则表达式的用法
由于-name参数只支持“*”、"?"、“[]”这三个通配符,因此在碰到负责的匹配希求时,就会用到正则表达式。
find正则表达式的语法如下:
find pathname -rgextype "type" -rgex "pattern"
示例代码如下:
[root@centos7 /data]# find / -regex "find" #给出的正则表达式必须要匹配完整的文件路径。
[root@centos7 /data]# find / -regex ".*find"
/sys/kernel/debug/tracing/events/xfs/xfs_buf_find
/usr/bin/find
/usr/bin/oldfind
/usr/share/bash-completion/completions/find
/usr/src/kernels/3.10.0-957.el7.x86_64/include/config/generic/find
/usr/src/kernels/3.10.0-1127.19.1.el7.x86_64/include/config/generic/find
[root@centos7 /data]# find / -regex ".*/find"
/usr/bin/find
/usr/share/bash-completion/completions/find
/usr/src/kernels/3.10.0-957.el7.x86_64/include/config/generic/find
/usr/src/kernels/3.10.0-1127.19.1.el7.x86_64/include/config/generic/find
正则表达式的类型默认未emacs,还有posix-awk、posix-basic、posix-egrep和posix-entended等。下面是posix-entended的示例代码:
[root@centos7 /data]# find . -regextype "posix-egrep" -name '*[0-9]'
./dir1
./dir2
./dir3
需要说明的是:上面正则表达式的使用只是给大家拓展一下知识,在实际工作中用得比较少。
范例8-22: ls -l命令放在find命令的-exec选项中执行。
[root@centos7 /data]# find . -type f -exec ls -l {} ;
-rw-r--r--. 1 root root 22 Oct 9 18:16 ./neteagle.txt
-rw-r--r--. 1 root root 22 Oct 9 18:17 ./neteagle2.txt
-rw-r--r--. 1 root root 37 Oct 9 18:34 ./test.txt
-rw-r--r--. 1 555 555 0 Oct 10 20:34 ./file2.txt
#find命令匹配到了当前目录下的所有普通文件,并在-exec选项中使用ls -l命令将它们列出。
详细说明如下。
-exec后面跟的是command命令,最后以分号(;)作为结束标志,考虑到各个系统中分号会有不同的意义,所以前面要加反斜杠对分号进行转义。
这里需要注意如下几点。
-
{}的作用:值代前面find命令查找到的文件或目录。
-
{}前后都要有空格。
-
command可以是其他任何命令,例如示例代码中的ls、rm等命令。
范例8-23: 在目录中查找更改时间在n天以前的文件,并删除它们。
[root@centos7 /data]# find . -type f -mtime +14 -exec rm {} ; #find命令在目录中查找更改时间在14天以前的文件,并在-exec选项中使用rm命令将它们删除。范例8-24: 使用-exec选项对的安全模式-ok。
[root@centos7 /data]# find /var/log/ -name "*.log" -mtime +5 -ok rm {} ; < rm ... /var/log/anaconda/anaconda.log > ? n < rm ... /var/log/anaconda/X.log > ? n < rm ... /var/log/anaconda/program.log > ? ^C #find命令在/var/log/目录中查找所有文件名以.log结尾、更改时间在5天以前的文件,并删除它们,到此为止,-ok的功能与-exec一样,但是-ok还有一个功能,即在删除之前先给出提示,指出按y键表示删除文件,按n键表示不删除文件,这样操作会比较安全。范例8-25: 对查找到的文件内容显示属性信息。
[root@centos7 /data]# find . -type f|xargs ls -l #将find命令查到的普通文件通过管道符号和xargs命令传给ls命令执行。注意命令格式,这里使用了管道符合“|”,xargs是一个命令,是向其他命令传递参数的一个过滤器,大家可以先去阅读xargs命令的相关章节之后再来阅读此部分内容。 -rw-r--r--. 1 555 555 0 Oct 10 20:34 ./file2.txt -rw-r--r--. 1 root root 22 Oct 9 18:17 ./neteagle2.txt -rw-r--r--. 1 root root 22 Oct 9 18:16 ./neteagle.txt -rw-r--r--. 1 root root 37 Oct 9 18:34 ./test.txt范例8-26: 使用xargs执行mv命令的示例。
[root@centos7 /data]# ls a dir2 ext neteagle2.txt test xiaodong xingfujie dir1 dir3 file2.txt neteagle.txt test.txt xiaofen [root@centos7 /data]# find . -name "*.txt"|xargs -i mv {} dir2/ #使用xargs的-i参数,使得{}代表find查找到的文件,将这些文件以参数的形式放在mv命令后面,作为要移动的源文件,移动到dir2目录下。 [root@centos7 /data]# ls a dir1 dir2 dir3 ext test xiaodong xiaofen xingfujie [root@centos7 /data]# ls dir2/ file2.txt neteagle2.txt neteagle.txt test.txt范例8-27: find结合xargs的-p选项使用的示例。
[root@centos7 /data]# find dir2 -name "file*" |xargs -p rm -f rm -f dir2/file2.txt ?... [root@centos7 /data]# ls dir2/ file2.txt neteagle2.txt neteagle.txt test.txt #说明:使用xargs命令的-p选项会提示让你确认是否执行后面的命令,y表示执行,n表示不执行。
8.3.6.2.2 技巧性范例
范例8-28: 进入/root目录下的data目录,删除neteagle.txt文件。
这里提供了多种删除方法。
①cd /root/data #进入目录再删,不适用全路径,这样会更安全。
②find /root/data -type f -name "*neteagle.txt" |xargs rm -f
③find /root/data -type f -name "*neteagle.txt" -exec rm {} ;
提示: 在生产环境中删除文件推荐使用第②中方法,该方法能够尽可能地防止误删文件。
范例8-29: 在/neteagle目录及其子目录下的所有以扩展名“*.sh”结尾的文件中,将包含"./hostlist.txt"的字符串全部替换为“../idctest_iplist”。
说明:
此题用到了sed命令的替换功能,读者如果不是很懂,那么可以先看下sed命令之后再做这道题。
sed -i 's#./hostlist.txt#../idctest_iplist#g' 文件名
#使用sed替换文件内容,然后结合find命令找到需要替换的文件。
方法一:find+exec方法。
find /neteagle -name "*.sh" -exec sed -i 's#./hostlist.txt#../idctest_iplist#g' {} ;
方法二:find+xargs方法。
find /neteagle -name "*.sh" |xargs sed -i 's#./hostlist.txt#../idctest_iplist#g'
方法三:高效处理方法,find语句两端是反引号。
sed -i 's#./hostlist.txt#../idctest_iplist#g' `find /neteagle -name "*.sh"` #前面说过,如果一个命令语句中还有反引号,优先执行反引号中的命令。
范例8-30: 将/etc下所有的普通文件打包成压缩文件。
此题涉及了tar命令的用法,读者可以先学tar命令再来查看这道题。
方法一:使用反引号的方法。
[root@centos7 ~]# cd /data
[root@centos7 /data]# ls
a dir1 dir2 dir3 ext test xiaodong xiaofen xingfujie
[root@centos7 /data]# touch xiaofen/test.txt
[root@centos7 /data]# touch ext/test.txt
[root@centos7 /data]# touch test/test.txt
[root@centos7 /data]# tar zcvf neteagle.tar.gz `find /data -type f -name "test.txt"` #使用反引号的方法最简单,也最容易理解。
tar: Removing leading `/' from member names
/data/dir2/test.txt
/data/test/test.txt
/data/ext/test.txt
/data/xiaofen/test.txt
[root@centos7 /data]# ls
a dir2 ext test xiaofen
dir1 dir3 neteagle.tar.gz xiaodong xingfujie
[root@centos7 /data]# tar -tvf neteagle.tar.gz
-rw-r--r-- root/root 37 2020-10-09 18:34 data/dir2/test.txt
-rw-r--r-- root/root 0 2020-10-11 14:07 data/test/test.txt
-rw-r--r-- root/root 0 2020-10-11 14:07 data/ext/test.txt
-rw-r--r-- root/root 0 2020-10-11 14:07 data/xiaofen/test.txt
方法二:使用xargs的方法。
[root@centos7 /data]# find /data -type f -name "test.txt" |xargs tar zcvf neteagle01.tar.gz
tar: Removing leading `/' from member names
/data/dir2/test.txt
/data/test/test.txt
/data/ext/test.txt
/data/xiaofen/test.txt
[root@centos7 /data]# ls
a dir2 ext neteagle.tar.gz xiaodong xingfujie
dir1 dir3 neteagle01.tar.gz test xiaofen
[root@centos7 /data]# tar -tvf neteagle01.tar.gz
-rw-r--r-- root/root 37 2020-10-09 18:34 data/dir2/test.txt
-rw-r--r-- root/root 0 2020-10-11 14:07 data/test/test.txt
-rw-r--r-- root/root 0 2020-10-11 14:07 data/ext/test.txt
-rw-r--r-- root/root 0 2020-10-11 14:07 data/xiaofen/test.txt
本题答案:
tar zcvf neteagle.tar.gz `find /etc -type f`
find /etc -type f |xargs tar zcvf neteagle01.tar.gz
范例8-31: 删除一个目录下的所有文件,但保留一个指定文件。
假设这个目录是/xx/,里面有file1、file2、...file10等10个文件,保留一个指定的文件file10,其余的删除,示例代码如下:
[root@centos7 ~]# mkdir xx
[root@centos7 ~]# cd xx
[root@centos7 ~/xx]# touch file{1..10}
[root@centos7 ~/xx]# ls
file1 file2 file4 file6 file8
file10 file3 file5 file7 file9
方法一:使用find+xargs命令处理(推荐方法)。
[root@centos7 ~/xx]# find /root/xx -type f ! -name "file10" |xargs rm -f #核心是使用感叹号排除file10文件。
[root@centos7 ~/xx]# ls
file10
方法二:使用find+exec命令处理(文件多时效率低)。
[root@centos7 ~/xx]# touch file{1..10}
[root@centos7 ~/xx]# ls
file1 file2 file4 file6 file8
file10 file3 file5 file7 file9
[root@centos7 ~/xx]# find /root/xx -type f ! -name "file10" -exec rm -f {} ;
[root@centos7 ~/xx]# ls
file10
方法三:使用rsync命令处理(rsync命令后面会讲解)。
[root@centos7 ~/xx]# touch file{1..10}
[root@centos7 ~/xx]# ls
file1 file2 file4 file6 file8
file10 file3 file5 file7 file9
[root@centos7 ~/xx]# mkdir /null #建立一个空目录用于rsync删除文件使用。
[root@centos7 ~/xx]# rsync -az --delete --exclude "file10" /null /root/xx/
[root@centos7 ~/xx]# ls
file1 file2 file4 file6 file8 null
file10 file3 file5 file7 file9
[root@centos7 ~/xx]# ls null/
这部分内容请参考老男孩的博客:oldboy.blog.51cto.com/2561410/165…。
8.3.6.2.3 生产案例
范例8-32: 这是几年前笔者为一家IT公司做技术顾问时遇到的一个实际问题,当时一个lamo的服务器里,站点目录下的所有文件均被植入如下内容:
<script language=javascript
src=http://%4%66E%78%6F&72%67%2E&70%6F/x.js?
google_ad=93x28_ad></script>
包括图片文件也被植入了上述内容,网站打开时就会调用这个地址,显示一个广告,造成的影响很恶劣。虽然现在看起来这个问题很简单,但当时该公司Linux运维花了很久都没搞定,后来经笔者的指点,很快就搞定了。那么具体该如何解决呢?
解决思路是遍历所有的目录和所有的文件,把以上被植入的内容删除掉。
具体的处理过程如下。
1)与运维人员确认问题,并详细确认问题的情况。
2)指定处理方案,先备份数据,然后执行命令批量修改回来。
3)写下解决说明(类似本例这样),写完发给运维人员。
4)询问处理结果,并告知应详细查看日志,找出问题发生的根源。
5)提供亡羊补牢的解决方案(站点目录严格权限规划方案及新上线规范思路)。
从发现问题到解决问题的过程具体如下。
1)运营人员、网站用户发现问题,网站有弹窗广告。
2)运营人员报给开发人员,开发人员联系运维人员。开发和运维共同解决。
3)开发发现造成这个问题的原因就是所有站点目录下的文件均嵌入了一段js代码。
4)运维人员的解决办法是,先备份出问题的所有原始文件,然后用find+sed替换,如果有备份数据也可以将备份数据还原。
5)详细查看日志,寻找问题发生的根源。
6)提供亡羊补牢的解决方案(站点目录严格权限规划方案及新上线规范思路)。
示例代码如下:
[root@centos7 ~]# find . -type f |xargs sed -i 's#<script language=javascript
src=http://%4%66E%78%6F&72%67%2E&70%6F/x.js?
google_ad=93x28_ad></script>##g'
也可以直接清理指定的行,命令如下:
[root@centos7 ~]# find . -type f |xargs sed -i ‘/*x.js?google_ad*/d’
范例8-33: 已知Apache服务的访问日志按天记录在服务器本地目录/app/logs下,由于磁盘空间紧张,现在要求只能保留最近7天的访问日志!请问如何解决?
对于这个问题,可以从Apache服务配置上着手,也可以从生成出来的日志上着手。
首先,生成测试文件,脚本如下(命令行直接执行即可):
[root@centos7 ~/log]# vim for.sh
for n in `seq 14`
do
date -s "2020/10/$n"
touch accexx_www_` (date +%F) `.log
done
date -s "2020/10/11"
:wq
[root@centos7 ~/log]# sh for.sh
Thu Oct 1 00:00:00 CST 2020
Fri Oct 2 00:00:00 CST 2020
Sat Oct 3 00:00:00 CST 2020
Sun Oct 4 00:00:00 CST 2020
Mon Oct 5 00:00:00 CST 2020
Tue Oct 6 00:00:00 CST 2020
Wed Oct 7 00:00:00 CST 2020
Thu Oct 8 00:00:00 CST 2020
Fri Oct 9 00:00:00 CST 2020
Sat Oct 10 00:00:00 CST 2020
Sun Oct 11 00:00:00 CST 2020
Mon Oct 12 00:00:00 CST 2020
Tue Oct 13 00:00:00 CST 2020
Wed Oct 14 00:00:00 CST 2020
Sun Oct 11 00:00:00 CST 2020
生成的文件如下所示:
[root@centos7 ~/log]# ls
accexx_www_2020-10-01.log accexx_www_2020-10-09.log
accexx_www_2020-10-02.log accexx_www_2020-10-10.log
accexx_www_2020-10-03.log accexx_www_2020-10-11.log
accexx_www_2020-10-04.log accexx_www_2020-10-12.log
accexx_www_2020-10-05.log accexx_www_2020-10-13.log
accexx_www_2020-10-06.log accexx_www_2020-10-14.log
accexx_www_2020-10-07.log for.sh
accexx_www_2020-10-08.log
[root@centos7 ~/log]# date -s "2020/10/11"
Sun Oct 11 00:00:00 CST 2020
解决上述问题 的方法有如下四种:
① find . -type f -name "access.log" -mtime +7 |xargs rm -f
② find . -type f -name "access.log" -mtime +7 -exec rm -f {} ;
③ find . -type f -name "access.log" -mtime +7 -delete #-delete是find命令的参数,可以将查找的文件删除。
④从Apache服务配置上着手,用cronolog软件轮询日志
CustomLog "|usr/local/sbin/cronolog /app/logs/access_www_%w.log" combined
8.3.6.2.4 拓展知识:将找到的文件移动到指定位置的方法
将找到的文件移动到指定位置,可以采用如下几种经典方法(同样适用于cp复制场景)。
方法1:
find . -name "*.txt" |xargs -i mv {} dir2/ #xargs的-i参数使得{}可代替find找到的内容。
方法2:
find . -name "*.txt" |xargs mv -t dir2/ #mv命令的-t选项前面已经讲解过,可以颠倒源和目标。
方法3:
mv `find . -name "*.txt"` dir2/ #反引号``的作用是优先执行它包含的内容。
方法1中xargs的-i参数使得{}可代替find找到的内容,最终作为mv命令的源复制到dir2目录下。而方法2是利用mv的-t命令来颠倒源和目标的,因为find找到的结果通过xargs默认会作为命令的目标,即“mv dir2/ 目标”,这显然是错的。方法3是利用mv命令的基本用法,然后将find命令用反引号括起来作为源进行操作。
8.3.6.2.5 拓展知识:find命令结合exec和xargs使用的区别
find命令结合exec和xargs使用的区别具体见表8-10。
表8-10 find命令结合exec和xargs使用的区别
使用-exec选项命令操作的示例及结果如下:
[root@centos7 ~]# find . -type f -exec echo neteagle {} ; #从命令的执行结果中可以看到,每次获得一个文件就输出一次。
neteagle ./.bash_logout
neteagle ./.bash_profile
neteagle ./.bashrc
neteagle ./.cshrc
neteagle ./.tcshrc
neteagle ./anaconda-ks.cfg
neteagle ./.bash_history
neteagle ./.lesshst
neteagle ./test/.file4.txt
neteagle ./test/dir5/file1.txt
neteagle ./test/dir5/file2.txt
neteagle ./test/dir5/file6.txt
neteagle ./hello.txt
neteagle ./test.txt
neteagle ./test1.txt
neteagle ./test3.txt
neteagle ./opt_sysctl.sh
neteagle ./exportfs_usage.sh
neteagle ./menu.sh
neteagle ./test2.txt
neteagle ./neteagle.txt
neteagle ./neteagle2.txt
neteagle ./a.txt
neteagle ./b.txt
neteagle ./neteagle/neteagle.jpg
neteagle ./neteagle/arp.zip
neteagle ./neteagle/test.doc
neteagle ./neteagle/neteagle.ppt
neteagle ./neteagle20201010
neteagle ./file2.txt
neteagle ./neteagle.tar.gz
neteagle ./neteagle01.tar.gz
neteagle ./xx/file10
neteagle ./xx/file1
neteagle ./xx/file2
neteagle ./xx/file3
neteagle ./xx/file4
neteagle ./xx/file5
neteagle ./xx/file6
neteagle ./xx/file7
neteagle ./xx/file8
neteagle ./xx/file9
neteagle ./log/accexx_www_2020-10-11.log
neteagle ./log/for.sh
neteagle ./log/accexx_www_2020-10-01.log
neteagle ./log/accexx_www_2020-10-02.log
neteagle ./log/accexx_www_2020-10-03.log
neteagle ./log/accexx_www_2020-10-04.log
neteagle ./log/accexx_www_2020-10-05.log
neteagle ./log/accexx_www_2020-10-06.log
neteagle ./log/accexx_www_2020-10-07.log
neteagle ./log/accexx_www_2020-10-08.log
neteagle ./log/accexx_www_2020-10-09.log
neteagle ./log/accexx_www_2020-10-10.log
neteagle ./log/accexx_www_2020-10-12.log
neteagle ./log/accexx_www_2020-10-13.log
neteagle ./log/accexx_www_2020-10-14.log
neteagle ./.viminfo
使用xargs命令操作的示例及结果如下:
[root@centos7 ~]# find . -type f |xargs echo neteagle #输出结果只有一行,xargs获取到所有文件名一次性输出。
neteagle ./.bash_logout ./.bash_profile ./.bashrc ./.cshrc ./.tcshrc ./anaconda-ks.cfg ./.bash_history ./.lesshst ./test/.file4.txt ./test/dir5/file1.txt ./test/dir5/file2.txt ./test/dir5/file6.txt ./hello.txt ./test.txt ./test1.txt ./test3.txt ./opt_sysctl.sh ./exportfs_usage.sh ./menu.sh ./test2.txt ./neteagle.txt ./neteagle2.txt ./a.txt ./b.txt ./neteagle/neteagle.jpg ./neteagle/arp.zip ./neteagle/test.doc ./neteagle/neteagle.ppt ./neteagle20201010 ./file2.txt ./neteagle.tar.gz ./neteagle01.tar.gz ./xx/file10 ./xx/file1 ./xx/file2 ./xx/file3 ./xx/file4 ./xx/file5 ./xx/file6 ./xx/file7 ./xx/file8 ./xx/file9 ./log/accexx_www_2020-10-11.log ./log/for.sh ./log/accexx_www_2020-10-01.log ./log/accexx_www_2020-10-02.log ./log/accexx_www_2020-10-03.log ./log/accexx_www_2020-10-04.log ./log/accexx_www_2020-10-05.log ./log/accexx_www_2020-10-06.log ./log/accexx_www_2020-10-07.log ./log/accexx_www_2020-10-08.log ./log/accexx_www_2020-10-09.log ./log/accexx_www_2020-10-10.log ./log/accexx_www_2020-10-12.log ./log/accexx_www_2020-10-13.log ./log/accexx_www_2020-10-14.log ./.viminfo
xargs还能控制每行输出的参数个数,示例代码如下(更多使用方法见xargs命令):
[root@centos7 ~]# find . -type f |xargs -n 3 echo neteagle #使用-n 3指定每次输出3个参数。
neteagle ./.bash_logout ./.bash_profile ./.bashrc
neteagle ./.cshrc ./.tcshrc ./anaconda-ks.cfg
neteagle ./.bash_history ./.lesshst ./test/.file4.txt
neteagle ./test/dir5/file1.txt ./test/dir5/file2.txt ./test/dir5/file6.txt
neteagle ./hello.txt ./test.txt ./test1.txt
neteagle ./test3.txt ./opt_sysctl.sh ./exportfs_usage.sh
neteagle ./menu.sh ./test2.txt ./neteagle.txt
neteagle ./neteagle2.txt ./a.txt ./b.txt
neteagle ./neteagle/neteagle.jpg ./neteagle/arp.zip ./neteagle/test.doc
neteagle ./neteagle/neteagle.ppt ./neteagle20201010 ./file2.txt
neteagle ./neteagle.tar.gz ./neteagle01.tar.gz ./xx/file10
neteagle ./xx/file1 ./xx/file2 ./xx/file3
neteagle ./xx/file4 ./xx/file5 ./xx/file6
neteagle ./xx/file7 ./xx/file8 ./xx/file9
neteagle ./log/accexx_www_2020-10-11.log ./log/for.sh ./log/accexx_www_2020-10-01.log
neteagle ./log/accexx_www_2020-10-02.log ./log/accexx_www_2020-10-03.log ./log/accexx_www_2020-10-04.log
neteagle ./log/accexx_www_2020-10-05.log ./log/accexx_www_2020-10-06.log ./log/accexx_www_2020-10-07.log
neteagle ./log/accexx_www_2020-10-08.log ./log/accexx_www_2020-10-09.log ./log/accexx_www_2020-10-10.log
neteagle ./log/accexx_www_2020-10-12.log ./log/accexx_www_2020-10-13.log ./log/accexx_www_2020-10-14.log
neteagle ./.viminfo
验证区别二的案例:
[root@centos7 ~]# mkdir test2
[root@centos7 ~]# cd test2
[root@centos7 ~/test2]# touch "neteagle study" #创建一个文件名带有空格的特殊文件。
[root@centos7 ~/test2]# find . -name "*neteagle*" -exec ls -lh {} ; #使用-exec参数正常使用。
-rw-r--r--. 1 root root 0 Oct 11 00:35 ./neteagle study
[root@centos7 ~/test2]# find . -name "*study*" |xargs ls -lh
#使用xargs命令无法正常打印。
ls: cannot access ./neteagle: No such file or directory
ls: cannot access study: No such file or directory
8.3.7 xargs:将标准输入转换成命令行参数
8.3.7.1 命令详解
【命令星级】 ★★★★☆
【功能说明】
xargs命令是向其他命令传递命令行参数的一个过滤器,它能够将管道或标准输入传递的数据转换成xargs命令后所跟命令的命令行参数。
【语法格式】
xargs [option]
xargs [选项]
说明: xargs命令以及后面的选项之间至少要有一个空格。
【选项说明】
表8-11针对xargs命令的参数选项进行了说明。
表8-11 xargs命令的参数选项及说明
8.3.7.2 使用范例
范例8-34: 多行输入变单行的示例。
[root@centos7 ~]# cat >test.txt<<EOF #这是测试文本。
> 1 2 3 4 5 6
> 7 8 9
> 10 11
> EOF
[root@centos7 ~]# xargs <test.txt #将所有数字变成一行,注意xargs不能直接接文件,需要结合输入重定向符“<”。
1 2 3 4 5 6 7 8 9 10 11
范例8-35: 通过-n指定每行输出个数的示例。
[root@centos7 ~]# xargs -n 3 <test.txt #每行最多输出3个。
1 2 3
4 5 6
7 8 9
10 11
范例8-36: 自定义分隔符(使用-d功能)的示例。
[root@centos7 ~]# echo splitXsplitXsplitXsplitX #echo将文本打印到屏幕上。
splitXsplitXsplitXsplitX
[root@centos7 ~]# echo splitXsplitXsplitXsplitX |xargs -d X #以X作为分隔符。
split split split split
[root@centos7 ~]# echo splitXsplitXsplitXsplitX |xargs -d X -n 2 #以X作为分隔符且每行最多输出2个。
split split
split split
提示: 该参数类似于cut命令的-d参数以及sed参数的-s参数。
范例8-37: 参数-I(大写I)可以指定一个替换的字符串。
这个参数的功能不是很好理解,需要做个铺垫,使用xargs的-i选项可以让{}代替前面find命令找到的文件或目录,命令如下:
[root@centos7 ~]# mkdir dir1
[root@centos7 ~]# find . -name "*.log" |xargs -i mv {} dir1/ #这个例子在find命令中已经讲解过了。
[root@centos7 ~]# ls dir1/
accexx_www_2020-10-01.log accexx_www_2020-10-08.log
accexx_www_2020-10-02.log accexx_www_2020-10-09.log
accexx_www_2020-10-03.log accexx_www_2020-10-10.log
accexx_www_2020-10-04.log accexx_www_2020-10-11.log
accexx_www_2020-10-05.log accexx_www_2020-10-12.log
accexx_www_2020-10-06.log accexx_www_2020-10-13.log
accexx_www_2020-10-07.log accexx_www_2020-10-14.log
从上面的示例代码中可以看出,使用-i选项可以用{}代替find查找的结果,而-I选项可以指定其他字符代替{}。例如[]。
[root@centos7 ~]# mkdir test3
[root@centos7 ~]# cd test3
[root@centos7 ~/test3]# touch file{1..5..2}
[root@centos7 ~/test3]# ls
file1 file3 file5
[root@centos7 ~/test3]# mkdir dir2
[root@centos7 ~/test3]# ls
dir2 file1 file3 file5
[root@centos7 ~/test3]# find . -name "file*" |xargs -I [] cp [] dir2[root@centos7 ~/test3]# ls
dir2 file1 file3 file5
[root@centos7 ~/test3]# ls dir2/
file1 file3 file5
范例8-38: 结合find使用xargs的特殊案例。
我们常用的删除文件的安全方法是find . -type f -name "*.txt" |xargs rm -f。但有时这个方法还是会出现一些小问题。比如说在tmp目录下有一个名为“hello world.txt”的文件,这种情况应该如何删除它呢?
首先模拟创建看看,直接通过“touch hello world.txt”来创建时不行了,这样会创建两个文件。下面是两种创建方法。
[root@centos7 ~/test3]# cd /tmp
[root@centos7 /tmp]# ls
[root@centos7 /tmp]# touch "hello world.txt" #第一种创建方法。
[root@centos7 /tmp]# ls
hello world.txt
[root@centos7 /tmp]# touch hello\ everyone.txt #第二种创建方法,反斜线后有一个空格,此时反斜线对空格进行了转义。
[root@centos7 /tmp]# ls
hello everyone.txt
hello world.txt
这里先用find . -type f -name "*.txt" |xargs rm查看一下结果:
[root@centos7 /tmp]# find . -type f -name "*.txt" |xargs rm
rm: cannot remove ‘./hello’: No such file or directory
rm: cannot remove ‘world.txt’: No such file or directory
rm: cannot remove ‘./hello’: No such file or directory
rm: cannot remove ‘everyone.txt’: No such file or directory
出现上述问题的原因是xargs误认为它们的分隔符是空格,解决方法是以字符null分割输出,这时使用-0(零)选项,就可以正确执行了,命令如下:
[root@centos7 /tmp]# find . -type f -name "*.txt" -print0|xargs -0 rm -f
#这样就不会有问题了。
[root@centos7 /tmp]# ls
8.4 tar:打包压缩命令
8.4.1 命令详解
【命令星级】 ★★★★★
【功能说明】
tar是Linux系统里将多个文件打包在一起并且可以实现将打包的文件解压的命令。tar是系统管理员最常用的命令之一,tar命令不但可以实现对多个文件进行打包,还可以实现对多个文件打包后进行压缩。
打包是指将一大堆文件或目录变成一个总的文件,压缩则是将一个大的文件通过一些压缩算法变成一个小的文件。
【语法格式】
tar [option] [file]
tar [选项] [文件或目录]
说明: 在tar命令以及后面的选项里,每个元素之间至少要有一个空格。
【选项说明】
tar命令的参数选项的使用有点特殊,对于CentOS Linux来说“tar -z”和“tar z”效果相同,加或不加“-”这个符号都是可以的,这是重点。具体说明参数见表8-12。
表8-12 tar命令的参数选项及说明
,那么tar只会对链接文件本身打包,而不是对链接文件指向的真实文件打包,因此还需要额外使用-h选项将软链接文件对应的实体文件打包。
8.4.2.2 生产案例
范例8-44: 对/etc目录下所有的普通文件打包。
[root@centos7 /etc]# cd /etc
[root@centos7 /etc]# ls
abrt my.cnf.d
adjtime NetworkManager
aliases networks
...
#如果etc下包含有目录、普通文件等,那么怎样才能将普通文件找出来并打包在一个文件中?
[root@centos7 /etc]# cd ..
[root@centos7 /]# tar zcvf etc.tar.gz `find etc/ -type f` #使用find命令找到所有普通文件,在tar命令语句中嵌套一个反引号的find命令语句。
tar: Removing leading `/' from member names
/etc/fstab
/etc/crypttab
/etc/resolv.conf
/etc/grub.d/00_header
...
[root@centos7 /]# ll -h etc.tar.gz
-rw-r--r--. 1 root root 22M Oct 11 18:39 etc.tar.gz
8.4.3 经验技巧
在打包时,有以下经验技巧可供读者参考。
1)在打包一个目录之前,先进入到这个目录的上一级目录,然后执行打包命令,这是大部分情况下打包文件的规范操作流程。少数情况下,当打包需要完整的目录结构时,可以使用绝对路径进行打包,但是需要注意解压tar包时压缩包内的文件是否会覆盖原始文件。
2)打包模型为:tar zcf /路径/筐.tar.gz 相对路径/苹果。打包其实就是讲苹果放进筐里。
8.5 date:显示与设置系统时间
8.5.1 命令详解
【命令星级】 ★★★★★
【功能说明】
date命令用于显示当前的系统时间或设置系统时间。
【语法格式】
date [option] [+FORMAT]
date [选项] [+日期格式]
【选项说明】
表8-13针对date命令的参数选项进行了说明。
表8-13 date命令的参数选项及说明
8.5.2 使用范例
范例8-45: 常用时间格式测试例子。
大家可以对着上面的表格逐一测试参数,这里限于篇幅仅列举一部分:
[root@centos7 ~]# date +%y #显示年(短格式)。
20
[root@centos7 ~]# date +%Y #显示年(长格式)。
2020
[root@centos7 ~]# date +%m #显示月。
10
[root@centos7 ~]# date +%d #显示日。
11
[root@centos7 ~]# date +%H #显示小时。
18
[root@centos7 ~]# date +%M #显示分。
48
[root@centos7 ~]# date +%S #显示秒。
45
[root@centos7 ~]# date +%F #显示特殊格式日期(年-月-日)。
2020-10-11
[root@centos7 ~]# date +%T #显示特殊格式时间(时:分:秒)。
18:48:52
范例8-46: 通过-d显示指定字符串所描述的时间的示例。
[root@centos7 ~]# date +%F -d "-1day" #显示昨天(简洁写法)。
2020-10-10
[root@centos7 ~]# date +%F -d "yesterday" #显示昨天(英文写法)。
2020-10-10
[root@centos7 ~]# date +%F -d "-2day" #显示前天。
2020-10-09
[root@centos7 ~]# date +%F -d "+1day" #显示明天。
2020-10-12
[root@centos7 ~]# date +%F -d "tomorrow" #显示明天(英文写法)。
2020-10-12
[root@centos7 ~]# date +%F -d "+2day" #显示2天后。
2020-10-13
[root@centos7 ~]# date +%F -d "1month" #显示1个月后。
2020-11-11
[root@centos7 ~]# date +%F -d "1year" #显示1年后。
2021-10-11
#说明:这里的+号表示未来,-号表示过去,day表示日,year表示年,month表示月。
[root@centos7 ~]# date +%F -d "24hour"
2020-10-12
[root@centos7 ~]# date +%F -d "1440min"
2020-10-12
[root@centos7 ~]# date +%F -d "-1440min"
2020-10-10
说明: 这里的hour表示小时,min表示分。
范例8-47: 时间格式转换例子。
[root@centos7 ~]# date
Sun Oct 11 19:00:37 CST 2020
[root@centos7 ~]# date -d "Sun Oct 11 19:00:37 CST 2020" "+%Y-%m-%d %H:%M:%S"
2020-10-11 19:00:37
说明:
-d选项后面应接上需要转化的时间,最后再接上你想要输出的时间格式。
下面是一个企业面试题,要求转换日志的时间格式,解答该题会利用到上面的知识点,同时还会使用awk命令。
备用数据如下:
[root@centos7 ~]# cat >test.log<<EOF
> Sat May 19 13:40:02 CST 2019 is 13213213
> Sat May 19 19:37:43 CST 2019 is 1012122
> Sat May 19 13:40:03 CST 2019 is 13213213
> Sat May 19 19:37:42 CST 2019 is 1012122
> Sat May 19 13:40:03 CST 2019 is 13213213
> Sat May 19 19:37:43 CST 2019 is 1012122
> EOF
解答过程如下:
[root@centos7 ~]# awk -F "is" '{print "echo $( date -d " "$1"" "+%F %T " )",$2}' test.log
#对内容按照命令进行拼接。
echo $( date -d " Sat May 19 13:40:02 CST 2019 " "+%F %T " ) 13213213
echo $( date -d " Sat May 19 19:37:43 CST 2019 " "+%F %T " ) 1012122
echo $( date -d " Sat May 19 13:40:03 CST 2019 " "+%F %T " ) 13213213
echo $( date -d " Sat May 19 19:37:42 CST 2019 " "+%F %T " ) 1012122
echo $( date -d " Sat May 19 13:40:03 CST 2019 " "+%F %T " ) 13213213
echo $( date -d " Sat May 19 19:37:43 CST 2019 " "+%F %T " ) 1012122
[root@centos7 ~]# awk -F "is" '{print "echo $( date -d " "$1"" "+%F %T " )",$2}' test.log|bash
2019-05-19 13:40:02 13213213
2019-05-19 19:37:43 1012122
2019-05-19 13:40:03 13213213
2019-05-19 19:37:42 1012122
2019-05-19 13:40:03 13213213
2019-05-19 19:37:43 1012122
#命令说明:使用is作为分隔符,$1是“Sat May 19 13:40:02 CST 2019”,$2是“13213213”,首先使用date命令对原时间格式进行转换,然后利用awk拼凑出如下格式,最后使用bash执行命令。
范例8-48: 通过参数-s设定时间。
[root@centos7 ~]# date -s 20201008 #设置成20201008,具体时间为空即00:00:00。
Thu Oct 8 00:00:00 CST 2020
[root@centos7 ~]# date -s 00:00:03 #设置具体时间,不会对日期做更改。
Thu Oct 8 00:00:03 CST 2020
[root@centos7 ~]# date -s "00:00:03 20201008" #这样可以设置全部时间。
Thu Oct 8 00:00:03 CST 2020
[root@centos7 ~]# date -s "00:00:03 2020-10-08" #日期可使用不同的格式。
Thu Oct 8 00:00:03 CST 2020
[root@centos7 ~]# date -s "00:00:03 2020/10/08" #日期可使用不同的格式。
Thu Oct 8 00:00:03 CST 2020
8.6 本章重点
1)Linux中的文件类型知识。
2)重点要掌握的命令:which、find、xargs、tar、date。