首页 > > > Linux命令学习手册-find
`find pathname -options [-print -exec -ok ...]`
# 功能
`find` 用于查找符合某些特性的文件。由于 `find` 具有强大的功能,所以它的选项也很多,其中大部分选项都值得我们花时间来了解一下。
即使系统中含有网络文件系统( NFS), `find` 命令在该文件系统中同样有效,只要你具有相应的权限。
# 描述
## `find` 命令的参数
`find` 的所有参数均为可选
- `pathname` : `find` 命令所查找的目录路径。例如用.来表示当前目录,用 `/` 来表示系统根目录。
- `-print` : `find` 命令将匹配的文件输出到标准输出。
- `-exec` : `find` 命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为 `command { } \;` ,注意 `{ }` 和 `\;` 之间的空格。
- `-ok` : 和 `-exec` 的作用相同,只不过以一种更为安全的模式来执行该参数所给出的shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。
## `find` 命令选项
- `-name` 按照文件名查找文件。
- `-perm` 按照文件权限来查找文件。
- `-prune` 使用这一选项可以使 `find` 命令不在当前指定的目录中查找,如果同时使用 `-depth` 选项,那么 `-prune` 将被 `find` 命令忽略。
- `-user` 按照文件属主来查找文件。
- `-group` 按照文件所属的组来查找文件。
- `-mtime -n +n`
按文件更改时间来查找文件, `-n` 表示文件更改时间距现在 `n` 天以内, `+n` 表示文件更改时间距现在 `n` 天以前。 `find` 命令还有 `-atime` 和 `-ctime` 选项,但它们都和 `-m time` 选项。
- `-nogroup` 查找无有效所属组的文件,即该文件所属的组在 `/etc/groups` 中不存在。
- `-nouser` 查找无有效属主的文件,即该文件的属主在 `/etc/passwd` 中不存在。
- `-newer file1 ! file2` 查找更改时间比文件 `file1` 新但比文件 `file2` 旧的文件。
- `-type`
查找某一类型的文件,诸如:
- `b` 块设备文件。
- `d` 目录。
- `c` 字符设备文件。
- `p` 管道文件。
- `l` 符号链接文件。
- `f` 普通文件。
- `-size n [cwbkMG]` : 查找文件长度为 `n` 块的文件,带有 `c` 等时表示文件长度(如 `c` 表示字节计)。
- `-depth` :在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
- `-fstype` :查找位于某一类型文件系统中的文件,这些文件系统类型通常可以在配置文件 `/etc/fstab` 中找到,该配置文件中包含了本系统中有关文件系统的信息。
- `-mount` :在查找文件时不跨越文件系统 `mount` 点。
- `-follow` :如果 `find` 命令遇到符号链接文件,就跟踪至链接所指向的文件。
- `-cpio` :对匹配的文件使用 `cpio` 命令,将这些文件备份到磁带设备中。
另外,下面三个的区别:
- `-amin n` 查找系统中最后N分钟访问的文件
- `-atime n` 查找系统中最后n\*24小时访问的文件
- `-cmin n` 查找系统中最后N分钟被改变文件状态的文件
- `-ctime n` 查找系统中最后 `n*24` 小时被改变文件状态的文件
- `-mmin n` 查找系统中最后N分钟被改变文件数据的文件
- `-mtime n` 查找系统中最后 `n*24` 小时被改变文件数据的文件
## 使用 `exec` 或 `ok` 来执行shell命令
使用 `find` 时,只要把想要的操作写在一个文件里,就可以用 `exec` 来配合 `find` 查找,很方便的。
在有些操作系统中只允许 `-exec` 选项执行诸如 `ls` 或 `ls -l` 这样的命令。大多数用户使用这一选项是为了查找旧文件并删除它们。建议在真正执行 `rm` 命令删除文件之前,最好先用 `ls` 命令看一下,确认它们是所要删除的文件。
`exec` 选项后面跟随着所要执行的命令或脚本,然后是一对儿 `{ }` ,一个空格和一个 `\` ,最后是一个分号。为了使用 `exec` 选项,必须要同时使用 `print` 选项。如果验证一下 `find` 命令,会发现该命令只输出从当前路径起的相对路径及文件名。
# 举例
## 按名称
### 在当前目录中查找任何扩展名为 `.c` 的文件:
$find ./ -name '*.c'
或
$find ./ -name \*.c
或
$find -name '*.c'
输入之后,输出如下:
./hello.c
./1/main.c
./1/hello.c
./hello2.c
这里,当前目录只用 `.` 也行,如果不用转义, `*.c` 必须括在引号(单/双)当中,如果不指定路径,将在当前目录找; 默认把子目录下的也都找出来了。
### 到 `./test` 、 `./viStudy` 目录查找所有 `.c` 文件:
$find test viStudy/ -name '*.c'
输入之后,输出如下:
test/test_out_direct.c
viStudy/hello.c
viStudy/1/main.c
viStudy/1/hello.c
viStudy/hello2.c
这里,如果您没有相应的权限,您在开始浏览许多目录时将生成错误消息例如如下的提示:
find: /tmp/orbit-root: Permission denied
可以不让错误输出,防止混乱:
$find /usr /home /tmp -name "*.jar" 2>/dev/null
### 不区分大小写的 `find` 查找:
$find downloads -iname '*.gif'
输入之后,输出如下:
downloads/.xvpics/Calendar05_enlarged.gif
downloads/lcmgcfexsmall.GIF
这里,默认情况下, `find` 是区分大小写的。对于不区分大小写的 `find` ,将 `-iname` 测试替换为 `-name` 。
### 列出当前目录和所有子目录中的所有文件(包括隐藏文件)的完整清单:
$find
或
$find .
或
$find . -print
输入之后,输出如下:
.
./any
./tags
./hello.c
./1
./1/main.c
...省略...
## 按类型
### 查找某(当前)目录中的所有子目录:
$find . -type d
或
$find -type d
输入之后,输出如下:
.
./1
### 查找某(当前)目录中的所有符号链接:
$find . -type l
输入之后输出如下:
./hello2s
这里, `./hello2s` 是一个软链接,这个命令显示的也是软链接。其他 `find` 可以找到的文件类型包括:
- `b` — 块(缓存)特殊
- `c` — 字符(未缓存)特殊
- `p` — 命名管道 (FIFO)
- `s` — 套接字
用 `ls` 列出软链接需要用 `-ls` ,用管道不行。如下:
$find . type l -ls
输出:
56231215 0 lrwxrwxrwx 1 quietheart member 6 May 16 16:14 ./hello2s -> hello2
### 从当前目录开始查找位于本文件系统中文件名以XC结尾的文件:
$ find . -name "*.XC" -mount -print
这里,在当前的文件系统中查找文件(不进入其他文件系统),使用了 `find` 命令的 `mount` 选项。
### 告知 `find` 在指定文件系统(例如 `vfat` )中查找:
$find / -name "*.txt" -fstype vfat
还有
$find / -name "*.txt" -mount 2
等等,不常用就不多说了。
## 按时间
### 查找在最近 1 \*24小时内修改的所有文件:
$find . -mtime -1
输入之后输出如下:
./plsql/FORALLSample
./plsql/RegExpDNASample
/plsql/RegExpSample
### 查找恰好在 1 \*24小时以前修改的所有文件:
$find . -mtime 1
### 查找 1 \*24个多小时以前修改的所有文件:
$find . -mtime +1
这里, `find` 根据系统的时间戳搜索文件的选项。这些时间戳包括:
- `mtime` — 文件内容上次修改时间
- `atime` — 文件被读取或访问的时间
- `ctime` — 文件状态变化时间
这里, `ctime` 则需要更多的解释。由于 `inode` 维护着每个文件上的元数据,因此,如果与文件有关的元数据发生变化,则 inode 数据也将变化。这可能是由一系列操作引起的,包括创建到文件的符号链接、更改文件权限或移动了文件等。由于在这些情况下,文件内容不会被读取或修改,因此 `mtime` 和 `atime` 不会改变,但 `ctime` 将发生变化。
这些时间选项都需要与一个值 `n` 结合使用,指定为 `-n` 、 `n` 或 `+n`:
- `-n` 返回项小于 `n`
- `+n` 返回项大于 `n`
- `n` 返回项正好与 `n` 相等
### 查找在不到 1 分钟以前读取的所有文件:
$find . -amin -1
输入之后,输出如下:
./.bashrc
/.bash_history
./.xauthj5FCx1
这里是刚刚登陆系统就运行了这个命令,所以输出这样。默认情况下, `-mtime` 、 `-atime` 和 `-ctime` 指的是最近 24 小时。但是,如果它们前面加上了开始时间选项,则 24 小时的周期将从当日的开始时间算起。您还可以使用 `mmin` 、 `amin` 和 `cmin` 查找在不到 1 小时的时间内变化了的时间戳。
另外,应该注意的是,使用 `find` 命令查找文件本身将更改该文件的访问时间作为其元数据的一部分。
### 查找在当前目录中 `hello2.c` 文件之后被编辑过的所有文件:
$find . -newer hello2.c
输入之后输出如下:
.
./hello2s
./hello2h
./hello2
这里,需要注意硬链接的特殊性(我不说,只有你明白了才知道我说的意思)。使用 `-newer` 、 `-anewer` 和 `-cnewer` 选项与特定的文件比较查找已修改或访问过的文件。这类似于 `-mtime` 、 `-atime` 和 `-ctime` 。
- `-newer` 指内容最近被修改的文件
- `-anewer` 指最近被读取过的文件
- `-cnewer` 指状态最近发生变化的文件
### 查找更改时间比文件httpd1.conf新但比文件temp旧的文件:
$find -newer httpd1.conf ! -newer temp -ls
其中, `!` 是逻辑非符号。
## 按大小
### 查找所有大于 5MB 的用户文件:
$find / -size +5000000c 2> /dev/null
输入之后,输出如下:
/var/log/lastlog
/var/log/cups/access_log.4
/var/spool/mail/bluher
这里,把错误的信息定位到 `/dev/null` 了。
结尾的 `c` 以字节为单位报告我们的结果。默认情况下, `find` 以 512 字节块的数量报告大小。如果我们将 `c` 替换为 `k` ,我们还会看到以千字节的数量报告的结果,如果使用 `w` ,则会看到以两字节字的数量报告的结果。
### 在当前目录下查找长度超过10块的文件(一块等于512字节):
$ find . -size +10 -print
### 搜索所有零字节文件并将它们移至 /tmp/zerobyte 文件夹:
$find test -type f -size 0 -exec mv {} /tmp/zerobyte \;
这里, `-exec` 操作允许 `find` 在它遇到的文件上执行任何 `shell` 命令。在本文的后面部分,您将看到其用法的更多示例。大括号允许移动每个空文件。
### 查找test目录下的空文件:
$find test -empty
输入之后输出如下:
test/foo
test/test
查找空文件用的是 `-empty` 选项。
## 按权限、所属
### 在当前目录下查找文件权限位为 `755` 的文件:
$find . -perm 755 -print
还有一种表达方法:在八进制数字前面要加一个横杠 `-` ,表示都匹配,如 `-007` 就相当于 `777` , `-006` 相当于 `666` .
### 查找属于 `user1name` 或着属于 `user2name` 的文件:
$find / -user user1name -or -user user2name
### 查找既属于 `user1name` 又属于 `user2name` 用户的文件:
$find / -user user1name -and -user2name
### 查找在系统中属于非用户( `?` )的文件:
$find /-nouser
### 查找在系统中属于 `username` 的文件:
$find / -user username
### 查找在系统中属于 `groupname` 的文件:
$find / -group groupname
## 按指定目录
### 希望在 `/apps` 目录下查找文件,但不希望在 `/apps/bin` 目录下查找:
$find /apps -path "/apps/bin" -prune -o -print
在使用 `-prune` 选项时要当心,因为如果你同时使用了 `-depth` 选项,那么 `-prune` 选项就会被 `find` 命令忽略。
### 在 `/usr/sam` 目录下查找不在 `dir1` 子目录之内的所有文件:
$find /usr/sam -path "/usr/sam/dir1" -prune -o -print
这里, `find [-path ..] [expression]` 在路径列表的后面的是表达式。
`-path "/usr/sam" -prune -o -print` 是 `-path "/usr/sam" -a -prune -o -print` 的简写表达式按顺序求值, `-a` 和 `-o` 都是短路求值,与 shell 的 `&&` 和 `||` 类似。
如果 `-path "/usr/sam"= 为真,则求值 =-prune` , `-prune` 返回真,与逻辑表达式为真;否则不求值 `-prune` ,与逻辑表达式为假。
如果 `-path "/usr/sam" -a -prune` 为假,则求值 `-print` , `-print` 返回真,或逻辑表达式为真;否则不求值 `-print` ,或逻辑表达式为真。
这个表达式组合特例可以用伪码写为
if -path "/usr/sam" then
-prune
else
-print
### 避开多个文件夹:
$find /usr/sam \( -path /usr/sam/dir1 -o -path /usr/sam/file1 \) -prune -o -print
这里,圆括号表示表达式的结合。 `\` 表示引用,即指示 shell 不对后面的字符作特殊解释,而留给 `find` 命令去解释其意义。
### 确保先在一个目录中进行查找,然后才在其子目录中进行查找:
$find -name "*test*" -depth
输入之后,输出:
./test/test
./test
./localbin/test
./localbin/test_shell_var
./localbin/test.txt
./test2/test/test
./test2/test
./test2
### 让 `find` 在至少下至目录树三个级别的目录中查找:
$find / -mindepth 3 -name "*log"
### 在目录树的前三个级别中查找日志文件:
$find / -maxdepth 3 -name "*log"
## 查找并执行命令:
### 用 =ls -l=命令列出所匹配到的文件:
$find . -type f -exec ls -l { } \;
输入之后,输出:
-rw-r--r-- 1 root root 34928 2003-02-25 ./conf/httpd.conf
-rw-r--r-- 1 root root 12959 2003-02-25 ./conf/magic
-rw-r--r-- 1 root root 180 2003-02-25 ./conf.d/README
这里, `exec` 选项后面跟随着所要执行的命令或脚本,然后是一对儿 `{}` ,一个空格和一个 `\` ,最后是一个分号,注意 `{}` 内可以没有空格,但是 `{}` 后面、 `\` 前面要有一个空格。
### 在 `/logs` 目录中查找更改时间在5日以前的文件并删除它们:
$find logs -type f -mtime +5 -exec rm { } \;
在shell中用任何方式删除文件之前,应当先查看相应的文件,一定要小心!当使用诸如 `mv` 或 `rm` 命令时,可以使用 `-exec` 选项的安全模式。
### 当前目录中查找所有文件名以 `.LOG` 结尾、更改时间在5日以上的文件并删除,删除之前先给提示:
$find . -name "*.conf" -mtime +5 -ok rm { } \;
输入之后,输出如下提示:
< rm ... ./conf/httpd.conf > ? n
这里,按 `y` 键删除文件,按 `n` 键不删除。
### 匹配所有文件名为 `passwd*` 的文件,然后执行 `grep` 命令看这些文件中是否存在 `sam` 用户:
$find /etc -name "passwd*" -exec grep "sam" { } \;
输入之后,输出:
sam:x:501:501::/usr/sam:/bin/bash
### 当前目录中文件属主具有读、写权限,并且文件所属组的用户和其他用户具有读权限的文件:
$find . -type f -perm 644 -exec ls -l { } \;
### 查找 `/var/logs` 目录中更改时间在7日以前的普通文件,并在删除之前询问它们:
$find /var/logs -type f -mtime +7 -ok rm { } \;
### 查找系统中所有属于 `root` 组的文件:
$find . -group root -exec ls -l { } \;
输入之后,输出:
-rw-r--r-- 1 root root 595 10月 31 01:09 ./fie1
这里实际不用 `-exec` 也行,即: `$find . -group root` 。不过为了更详细列出相关的信息,使用 `exec` 选项对每个文件执行了 `ls` 。
### 查找并删除访问时间在7日以来、含有数字后缀的 `admin.log` 文件:
$find . -name "admin.log[0-9][0-9][0-9]" -atime -7 -ok rm { } \;
输入之后,输出:
< rm ... ./admin.log001 > ? n
< rm ... ./admin.log002 > ? n
< rm ... ./admin.log042 > ? n
< rm ... ./admin.log942 > ? n
这里,只寻找了3位数的数字。
## 高效的查找执行:
使用 `find` 命令的 `-exec` 选项处理匹配到的文件时, `find` 命令将所有匹配到的文件一起传递给 `exec` 执行。但有些系统对能够传递给 `exec` 的命令长度有限制,这样在 `find` 命令运行几分钟之后,就会出现溢出错误;还可能导致有些系统进程过多,系统性能下降的问题,因而效率不高.
使用 `xargs` 命令则只有一个进程。另外,在使用 `xargs` 命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。
下面是 `xargs` 命令同 `find` 命令一起使用的一些例子:
### 查找系统中的每一个普通文件,然后使用xargs命令来测试它们分别属于哪类文件:
$find . -type f -print | xargs file
输入之后,输出:
./.kde/Autostart/Autorun.desktop: UTF-8 Unicode English text
./.kde/Autostart/.directory: ISO-8859 text\
...省略...
### 当前目录下查找 `file` 开头的文件然后把结果保存到 `/tmp/core.log` 文件中:
$find . -name "file*" -print | xargs echo "" > /temp/core.log
### 在当前目录下查找所有用户具有读、写和执行权限的文件,并收回相应的写权限:
$find . -perm -7 -print | xargs chmod o-w
### 用 `grep` 命令在当前目录下的所有的普通文件中搜索 `hostname` 这个词:
$find . -type f -print | xargs grep "hostname"
或
$find . -name \* -type f -print | xargs grep "hostname"
输入之后,输出:
./httpd1.conf:# different IP addresses or hostnames and have them handled by the
./httpd1.conf:# VirtualHost: If you want to maintain multiple domains/hostnames on your
注意,这里, `\` 用来取消 `find` 命令中的 `*` 在shell中的特殊含义。
# 其它
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/9525959/viewspace-3128812/ ,如需转载,请注明出处,否则将追究法律责任。