Linux指令之find
2022-05-21 20:07:21 阿炯

在linux中,find命令用于在指定目录下查找文件,基本语法“find path -option..”。任何位于参数之前的字符串都将被视为欲查找的目录名;如果使用该命令时,不设置任何参数,则find命令将在当前目录下查找子目录与文件。

格式:
find path -option [ -print ] [ -exec -ok |xargs  |grep [ ] command {} \; ]
find path -option [ -print ] [ -exec -ok command ] {} \;

参数:

1)path:要查找的目录路径。~ 表示$HOME目录;. 表示当前目录;/ 表示根目录

2)print:表示将结果输出到标准输出,默认的处理动作

3)exec:对匹配的文件执行该参数所给出的shell命令。形式为command {} \;,注意{}与\;之间有空格

4)ok:与exec作用相同,区别在于在执行命令之前,都会给出提示,让用户确认是否执行

5)|xargs 与exec作用相同,起承接作用,区别在于 |xargs 主要用于承接删除操作 ,而 -exec 都可用 如复制、移动、重命名等

6)options:表示查找方式,常用的有下选项:
-name filename #查找名为filename的文件

options有以下几种查找方式:
按照名字查找(-name)
按照安装权限进行查找(-perm)
不在当前指定的目录下寻找(-prune)
按照文件属主来查找(-user)
按照文件的所属组来查找(-group)
查找没有有效的所属组文件(-nogroup)
查找没有有效属主的文件(-nouser)
按照文件类型来查找(-type)

-uid 用户ID    #按用户ID査找所有者是指定 ID 的文件
-gid 组ID    #按用户组ID査找所属组是指定 ID 的文件
-user 用户名    #按用户名査找所有者是指定用户的文件
-group 组名    #按组名査找所属组是指定用户组的文件
-nouser    #査找没有所有者的文件

Linux 中的文件有访问时间(atime)、数据修改时间(mtime)、状态修改时间(ctime)这三个时间
-mtime -n +n    #按文件更改时间来查找文件,-n指n天以内,+n指n天以前
-atime  -n +n    #按文件访问时间来查找文件,-n指n天以内,+n指n天以前(不含n天本身)
-ctime  -n +n    #按文件创建时间来查找文件,-n指n天以内,+n指n天以前(含n天本身)

最近访问时间 access time (-atime)、最近更改时间 modify time (-mtime) 和最近状态改动时间 change time(-ctime)。

atime:它代表着最近一次访问文件的时间,显示一个文件的内容或者运行一个shell脚本会更新文件的atime。可用ls -lu命令查看。在2.6.30内核之前,文件系统中默认会及时的更新atime,而在此之后的版本里,只有发生以下三种情况之一才会更新atime:将分区mount的挂载的时候指定采用非relatime方式;atime小于ctime或者小于mtime的时候。

mtime:它代表着最近一次文件内容被修改的时间,可用ls -l 命令查看。

ctime:它代表着最近一次文件状态改变的时间,是status change time,是在写入文件、更改所有者、权限或链接设置时随 Inode 的内容更改而更改,即文件状态最后一次被改变的时间。可用ls -lc 命令查看。


做一个时间轴来解释一下,如下图所示。



"-5"代表 5 天内修改的文件,而"+5"总有人说代表 5 天修改的文件。所以"-5"指的是 5 天内修改的文件,"5"指的是前 5~6 天那一天修改的文件,"+5"指的是 6 天前修改的文件。

找 “5天之内被更改过的档案名” 就是find / -mtime -5;找“5天前的那一天被更改过的档案名” 就是find / -mtime 5;找“5天之前被更改过的档案名” 就是find / -mtime +5。可以看出有没有 “+,-”的差别是很大的,下面用图来说明一下:


由这个时光轴我们可以知道,最右边为当前时,+5 代表大于等于 6 天前的档案名,-5 代表小于等于 5 天内的档案名,5 则是代表 5-6 那一天的档案名。

也可以按照 amin、mmin 和 cmin 来査找文件的时间,区别只是所有 time 选项的默认单位是天,而 min 选项的默认单位是分钟。

-nogroup    #查无有效属组的文件,即文件的属组在/etc/groups中不存在
-nouser    #查无有效属主的文件,即文件的属主在/etc/passwd中不存

-type    b/d/c/p/l/f    #查是块设备(b)、目录(d)、字符设备(c)、管道(p)、符号链接(l)、普通文件(f)、套接字(s)

-size    n[c]    #查长度为n块[或n字节]的文件,-size[+-],"+"的意思是搜索比指定大小还要大的文件,"-",千字节必须是小写的"k",而兆字节必领是大写的"M"。
-size    n[cwbkMG]    File uses n units of space. [+|-]#UNIT,常用单位:k, M, G,c(byte). The following suffixes can be used:
'b' for 512-byte blocks (this is the default if no suffix is used)
#这是默认单位,如果单位为b或不写单位,则按照512Byte搜索
'c' for bytes
#搜索单位是c,按照字节搜索
'w' for two-byte words
#搜索单位是w,按照双字节(中文)搜索
'k'for Kilobytes (units of 1024 bytes)
#按照KB单位搜索,必须是小写的k
'M' for Megabytes (units of 1048576 bytes)
#按照MB单位搜索,必须是大写的M
'G' for Gigabytes (units of 1073741824 bytes)
#按照GB单位搜索,必须是大写的G
也就是说,如果想要按照字节搜索,则需要加搜索单位"c"。

-mount, -xdev    #查文件时不跨越文件系统mount点,即只检查和指定目录在同一个文件系统下的文件,避免列出其它文件系统中的文件

-follow    #如果遇到符号链接文件,就跟踪链接所指的文件

-perm    #权限模式,按指定的权限查找对应的文件,支持[+/-]选项。
-perm 权限模式:査找文件权限刚好等于"权限模式"的文件
-perm -权限模式:査找文件权限全部包含"权限模式"的文件
-perm +权限模式:査找文件权限包含"权限模式"的任意一个权限的文件

-prune    #忽略某个目录,任何位于参数之前的字符串都将被视为欲查找的目录名

-pid n : process id 是 n 的文件

-empty    file-or-dir    #查找空的文件或目录

-name: 按照文件名搜索;
-iname: 按照文件名搜索,不区分文件名大小;
-inum: 按照 inode 号搜索;每个文件都有inode号,如果知道其inode号,则可以按照inode号来搜索文件。按照 inode 号搜索文件,也是区分硬链接文件的重要手段,因为硬链接文件的 inode 号是一致的

-ipath p, -path p:路径名称符合 p 的文件,ipath 会忽略大小写


-links n #查找硬链接数为n的文件

-regex "PATTERN"    #以PATTERN匹配整个文件路径字符串,而不仅仅是文件名称


逻辑运算符

选项:
-a:and逻辑与
-o:or逻辑或
-not:not逻辑非

1)-a:and逻辑与
find 命令也支持逻辑运算符选项,其中 -a 代表逻辑与运算,也就是 -a 的两个条件都成立,find 搜索的结果才成立。
$ find.-size +2k -a -type f
#在当前目录下搜索大于2KB,并且文件类型是普通文件的文件

上例中,文件既要大于 2KB,又必须是普通文件,find 命令才可以找到。再举一个例子:
$ find.-mtime -3 -a -perm 644
#在当前目录下搜索3天以内修改过,并且权限是644的文件。

2)-o:or逻辑或
-o 选项代表逻辑或运算,也就是 -o 的两个条件只要其中一个成立,find 命令就可以找到结果。例如:
$ find.-name cangls -o -name bols
./cangls
./bols

#在当前目录下搜索文件名要么是cangls的文件,要么是bols的文件
-o 选项的两个条件只要成立一个,find 命令就可以找到结果,所以这个命令既可以找到 cangls 文件,也可以找到 bols 文件。

3)-not:not 逻辑非 (!)
-not是逻辑非,也就是取反的意思:
$ find . -not -name cangls
#在当前目录下搜索文件名不是cangls的文件


如果使用该命令时,不设置任何参数,则 find 命令将在当前目录下查找子目录与文件。并且将查找到的子目录和文件全部进行显示。下面通过一些简单的例子来介绍下find的常规用法:

1、按名字查找
在当前目录及子目录中,查找大写字母开头的txt文件
$ find . -name '[A-Z]*.txt' -print

在/etc及其子目录中,查找host开头的文件
$ find /etc -name 'host*' -print  

在$HOME目录及其子目录中,查找所有文件
$ find ~ -name '*' -print

在当前目录及子目录中,查找不是out开头的txt文件
$ find . -name "out*" -prune -o -name "*.txt" -print

2、按目录查找
在当前目录除aa之外的子目录内搜索txt文件
$ find . -path "./aa" -prune -o -name "*.txt" -print  

在当前目录及除aa和bb之外的子目录中查找txt文件
$ find . \( -path './dir0' -o -path './dir1' \) -a -prune -o -name '*.txt' -print

在当前目录,不再子目录中,查找txt文件
$ find . ! -name "." -type d -prune -o -type f -name "*.txt" -print
或者
$ find . -name *.txt -type f -print

查找属主不是freeoa或者uid不是500的文件
$ find / -user freeoa -o -uid 500

3、按权限查找
在当前目录及子目录中,查找属主具有读写执行,其他具有读执行权限的文件
$find . -perm 755 -print

查找用户有写权限或者组用户有写权限的文件或目录
find ./ -perm /220   
find ./ -perm /u+w,g+w   
find ./ -perm /u=w,g=w

4、按类型查找(b/d/c/p/l/f ) 
在当前目录及子目录下,查找符号链接文件
$ find . -type l -print

5、按属主及属组
查找属主是www的文件
$ find / -user www -type f -print

查找属主被删除的文件
$ find / -nouser -type f -print

查找属组 mysql 的文件
$ find / -group mysql -type f -print

查找用户组被删掉的文件
$ find / -nogroup -type f -print

6、按时间查找
查找2天内被更改过的文件
$ find . -mtime -2 -type f -print

查找2天前被更改过的文件
$ find . -mtime +2 -type f -print

查找一天内被访问的文件
$ find . -atime -1 -type f -print

查找一天前被访问的文件
$ find . -atime +1 -type f -print  

查找一天内状态被改变的文件
$ find . -ctime -1 -type f -print

查找一天前状态被改变的文件
$ find . -ctime +1 -type f -print  

查找10分钟以前状态被改变的文件
$ find . -cmin +10 -type f -print

7、按文件新旧
查找比 aa.txt 新的文件
$ find . -newer "aa.txt" -type f -print

查找比 aa.txt 旧的文件
$ find . ! -newer "aa.txt" -type f -print

查找比aa.txt新,比bb.txt旧的文件
$ find . -newer 'aa.txt' ! -newer 'bb.txt' -type f -print

8、按大小查找
查找超过1M的文件
$ find / -size +1M -type f -print

查找等于6字节的文件
$ find . -size 6c -print

查找小于32k的文件
$ find . -size -32k -print

9、执行命令
1)查找 del.txt 并删除,删除前提示确认
$ find . -name 'del.txt' -ok rm {} \;  

2) 查找 aa.txt 并备份为aa.txt.bak
$ find . -name 'aa.txt' -exec cp {} {}.bak \;

3)查当前目录下的所有普通文件
$ find . -type f -exec ls -l {} \;

查当前目录下的所有普通文件,并在 -exec 选项中使用 ls -l 命令将它们列出

4)在 /logs 目录中查找更改时间在5日以前的文件并删除它们
$ find logs -type f -mtime +5 -exec -ok rm {} \;

5)查询当天修改过的文件
$ find ./ -mtime -1 -type f -exec ls -l {} \;

6)查询文件并询问是否要显示
$ find ./ -mtime -1 -type f -ok ls -l {} \;  

10、其它指令参考
查找 /var/log 目录中更改时间在 7 日以前的普通文件,并在删除之前询问
$ find /var/log -type f -mtime +7 -ok rm {} \;

查找当前目录中文件属主具有读、写权限,并且文件所属组的用户和其他用户具有读权限的文件
$ find . -type f -perm 644 -exec ls -l {} \;

查找系统中所有文件长度为 0 的普通文件,并列出它们的完整路径
$ find / -type f -size 0 -exec ls -l {} \;

在/etc/中查找以conf结尾的文件
$ find /etc/ -regex ".*\.conf$"

查找/freeoa目录下的空文件夹(默认递归)
$ find /freeoa -type d -empty
$ find /data ! -empty -type f    #查找非空的文件

找/var目录下不属于root、lp、gdm的所有文件
$ find /var -not -user root -not -user lp -not -user gdm

查找/var目录下最近一周内其内容修改过,同时属主不为root,也不是postfix的文件
$ find /var -mtime -7 -not -user root -not -user postfix

查找/etc目录下所有用户都没有写权限的文件
$ find /etc -not -perm +222

查找/etc目录下至少有一类用户没有执行权限的文件
$ find /etc -not -perm -222


处理动作

-print:默认的处理动作,显示至屏幕

-ls:类似于对查找到的文件执行“ls -l”命令

find -perm +222 -ls 以长格式显示查找到的文件信息

-delete:删除查找到的文件

find -perm +222 -delete 直接删除查找到的内容不提示

-fls file:查找到的所有文件的长格式信息保存至指定文件中

find -perm +222 -ls > /tmp/find.log

find -perm +222 -fls /tmp/find2.log

以上两种方法均可以把查找到的文件的长格式内容重定向到文件中

-ok COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令,对于每个文件执行命令之前,都会交互式要求用户确认,下文有详述

删除的时候需要提示
find -name “*f*” -ok rm {} \;

直接批量删除不提示
find -name “*f*” -exec rm {} \;

把查找到的内容剪切到/freeoa/中
find -name “*f*” -exec mv {} /freeoa/ \;


-print的选项

当有-print选项时,查找目录并列出目录下的文件(为找到的每一个目录单独执行ls命令,没有选项-print时文件列表前一行不会显示目录名称)
find /home -type d -print -exec ls {} \;

-exec选项

主要讲解两个选项"-exec"和"-ok",这两个选项的基本作用非常相似。先来看看 "exec"选项的格式。

$ find 搜索路径 [选项] 搜索内容 -exec 命令2{}\;

首先,请注意这里的"{}"和"\;"是标准格式,只要执行"-exec"选项,这两个符号必须完整输入。

其次,这个选项的作用其实是把 find 命令的结果交给由"-exec"调用的命令 2 来处理。"{}"就代表 find 命令的査找结果。

示例如下,使用权限模式搜索只能看到文件名,例如:
$ find . -perm 444
./test2

如果要看文件的具体权限,还要用"ll"命令査看。用"-exec"选项则可以一条命令搞定:
$ find . -perm 444 -exec ls -l {}\;

-r--r--r-- 1 root root 0 6月 17 11:05 ./test2

#使用"-exec"选项,把find命令的结果直接交给"ls -l"命令处理,"-exec"选项的作用是把 find 命令的结果放入"{}"中,再由命令 2 直接处理。在这个例子中就是用"ls -l"命令直接处理,会使 find 命令更加方便。

-ok选项

"-ok"选项和"-exec"选项的作用基本一致,区别在于:"-exec"的命令会直接处理,而不询问;"-ok"的命令 2 在处理前会先询问用户是否这样处理,在得到确认命令后,才会执行。例如:
$ find . -perm 444 -ok rm -rf{}\;
<rm…./test2>?y  <-需要用户输入y,才会执行

使用rm命令来删除find找到的结果,删除的动作最好确认一下

Find Non-UTF8 Filenames on Linux File System
对于非UTF8的文件名会有如下的输出:
./\346\224\277\346\262\273/politi...

可借助perl来进行转换:
find path -name "可视化*" | perl -ne 'print if /[^[:ascii:]]/'