find 命令详解
find 命令是linux 世界中查找文件用的最多的一个命令
最简单的用法如下
find dir -d(depth) 1 -type f(f 文件 d 文件夹) -ctime -1d
-atime 最后的访问时间
s second
m minute (60 seconds)
h hour (60 minutes)
d day (24 hours)
w week (7 days)
Any number of units may be combined in one -atime argument, for
example, ``-atime -1h30m''. Units are probably only useful when
used in conjunction with the + or - modifier.
atime access time
mtime modify time
ctime create time
比如 -mtime +1 就是1天以上的 -1 一天以内的 1 1天或者一天以上的
不带单位 默认是d 【天】
可以使用 stat 查看具体的一个文件的详细信息
现在我们详细了解一下find 命令常用的参数
参数名称是什么 | 说明 |
---|---|
-name | 名字 可以是正则表达式 比如 -name '[a-z0-9]*.txt' 查找 名字的正则表达式 |
-perm | 权限 -perm 664 查找664的文件 ;还有一种表达方法:在八进制数字前面要加一个横杠-,表示至少包含这个权限; 查找权限为644的文件或目录(需完全符合) find ./ -perm 664 查找用户/组权限为读写,其他用户权限为读(其他权限不限)的文件或目录 find ./ -perm -664 |
-depth | 文件夹查找的深度 |
-prune | 去掉某一个目录 不进行查找;在使用-prune选项时要当心,因为如果你同时使用了-depth选项,那么-prune选项就会被find命令忽略。如果希望在test目录下查找文件,但不希望在test/test3目录下查找,可以用 find test -path "test/test3" -prune -o -print 这边 -path 是绝对路径 所以-path 最好是 "*test/test3" 这样的 |
-type | d 文件夹 f file l for link |
-exec | 对查找之后的内容进行 另外的操作 -exec ls {} \; 注意这个转义的 \; |
-ok | 加个一个确认 会在打印的时候确认 和 -exec 替换使用 只不过需要确认 比如上面的 -exec ls {} \; 变成了 -ok ls {} \; |
会打印查找的文件名字 全名 比如 find ~/Downloads/ -name "专供*" -print -exec cat {} \;· 会cat 文件的同时打印文件名称 如果没有 -print 的话没有 打印文件名称 |
|
-regex | 通过正则表达式查找 文件的名称 find ~/Downloads/ -regex .专供. -print -exec cat {} ; 查找的是全名 !!! 【这个比较烦 】 所有一定要注意 .*专供.* 前后的.* 可以查找特定文件夹 里面的特定的文件 |
-name | 根据名称查找文件 和正则表达式里面的* 不一样 * 这里匹配任意多个字符 |
-exec ls {} + | 这个加号的意思是将所有输出等到 最后一次性让 ls 执行 |
-atime 【 access time】 | find ./ -mtime -2d #查找两天内的文件 find ./ -mtime +2d #两天以上的 find ./ -mtime 2d #两天以上的以及两天以上的 注意的是哪怕ls 一下文件也会修改文件的access time 通过stat 查看 |
-mtime 【modified time 】 | 同上 |
-ctime 【changed time】 | 同上 |
-newer | 查找文件更新时间比文件abc的内容更新时间新的文件 find ./ -newer abc |
-anewer | 查找文件访问时间比文件abc的内容更新时间新的文件 find ./ -anewer abc |
-empty | 查找空文件 或者 空目录 |
-delete | 删除操作 比较危险 |
-user | user 用户 |
-group | group 筛选 |
-nouser | 没用户的 |
-nogroup | 没有group 的文件 |
find ./ -executable ! -readable | 查找有执行权限但没有可读权限的文件 这个完全可以在权限里面设置 这个readable 和 executable 只有在 centos linux 里面有 unix 木有 |
-size | 查找文件大小 |
-prune | 不包含文件夹 或者文件 |
-path <pattern> | 根据路径查找文件 复合pattern |
-perm 权限 的例子
查找权限为644的文件或目录(需完全符合)
find ./ -perm 664
查找权限不是 644 的文件或者目录
find ./ ! -perm 644 # ! 表示取反
查找用户/组权限为读写,其他用户权限为读(其他权限不限)的文件或目录
find ./ -perm -664
-664 包含的含义是“至少包含 644”
下面的含义是 other 包含 read
find ./ -perm -o=r 或者 find ./ -perm -o=rw # 里面的的选项有 -o -u -g 权限有 rwx
在centos 等linux 中还支持 find / -maxdepth 2 -perm /u=s 这样的的语法
-size 例子
查找文件size小于10个字节的文件或目录 find ./ -size -10c
查找文件size等于10个字节的文件或目录 find ./ -size 10c
查找文件size大于10个字节的文件或目录 find ./ -size +10c
查找文件size小于10k的文件或目录 find ./ -size -10k
查找文件size小于10M的文件或目录 find ./ -size -10M
查找文件size小于10G的文件或目录 find ./ -size -10G
-prune 的例子
参考 https://stackoverflow.com/questions/1489277/how-to-use-prune-option-of-find-in-sh
[-prune man 里面这样说 永远返回真,它让find 忽略满足条件的 目录,假如 -d 指定的话 这个参数无用]
The thing I'd found confusing about about -prune is that it's an action (like -print), not a test (like -name). It alters the "to-do" list, but always returns true. 【-prune更像是一个语句,就像-print 一样 】
The general pattern 【语法】for using -prune is this:
find [path] [conditions to prune] -prune -o \ [your usual conditions] [actions to perform]
You pretty much always want the the -o immediately after -prune, because that first part of the test (up to including -prune) will return false for the stuff you actually want (ie: the stuff you don't want to prune out). 所有 -prune 后面要紧跟 -o [-o -a 还有 ! 或 与 非] -o 后面的内容才是你 想要的
Here's an example:
find . -name .snapshot -prune -o -name '*.foo' -print
This will find the ".foo" files that aren't under ".snapshot" directories. In this example, -name .snapshot is the "tests for stuff you want to prune", and -name '.foo' -print is the "stuff you'd normally put after the path".
上面有一点错误 -name .snapshot 不仅是对文件夹的筛选,对文件一样的筛选【作者提示 一定要在-o 语句 最后加上 -print 否则也不会有效】
Important notes:
If all you want to do is print the results you might be used to leaving out the -print action. You generally don't want to do that when using -prune.
The default behavior of find is to "and" the entire expression with the -print action if there are no actions other than -prune (ironically) at the end. That means that writing this:
find . -name .snapshot -prune -o -name '*.foo' # DON'T DO THIS is equivalent to writing this:
find . ( -name .snapshot -prune -o -name '*.foo' ) -print # DON'T DO THIS
which means that it'll also print out the name of the directory you're pruning, which usually isn't what you want.
上面的意思是如果没有最后的print find 命令会将后面的所有条件综合起来 然后在最后加一个 -print 那样的话 -o 【or】 就失去了我们想要的结果
Instead it's better to explicitly specify the -print action if that's what you want: find . -name .snapshot -prune -o -name '*.foo' -print # DO THIS
If your "usual condition" happens to match files that also match your prune condition, those files will not be included in the output. The way to fix this is to add a -type d predicate to your prune condition.
下面是作者展示的一个例子 在本文件夹中既有一个文件叫 .gitignore 又有一个文件夹叫 .git 左右想剔除所有含有.git字样的文件夹但是想查看包含.git字样的文件
find ./ -type d -name ".git*" -prune -o -type f -print
For example, suppose we wanted to prune out any directory that started with .git (this is admittedly somewhat contrived -- normally you only need to remove thing named exactly .git), but other than that wanted to see all files, including files like .gitignore. You might try this:
find . -name '.git*' -prune -o -type f -print # DON'T DO THIS This would not include .gitignore in the output. Here's the fixed version: find . -type d -name '.git*' -prune -o -type f -print # DO THIS Extra tip: if you're using the GNU version of find, the texinfo page for find has a more detailed explanation than its manpage (as is true for most GNU utilities).
参考 http://www.cnblogs.com/peida/archive/2012/11/16/2773289.html
上面的文章有个例子讲到
-a 和 -o 都是短路求值,与 shell 的 && 和 || 类似如果
查看下面的例子
例子1
find . -path "*testone" -prune -a -exec ls -al {} \;
上面的例子 查找path 包含 testone 的文件 并把它打印出来 这个例子有点多此一举
相当于
find . -path "*testone" -exec ls -al {} \ ;
测试下来效果一样
例子2【摘抄】
避开多个文件夹: 命令: find test ( -path test/test4 -o -path test/test3 ) -prune -o -print
上面的例子很多人会测试失败原因是 -path 接受的是一个<pattern> 最好使用 *test4 代替 test/test4
我本地测试 避开 .git 和testone 文件夹
find . -type d -a ( -name ".git" -o -name "testone" ) -prune -o -print
一定要记得 -o !!!!
-depth 命令例子
参数-depth 的意思是:在处理目录以前首先处理目录下的子内容。 也即是说在不加-depth的时候, 处理顺序是首先处理目录本身,然后处理目录下的子内容。加不加-depth参数,会影响输出结构的输出顺序。
-mindepth 最少深度
dingmac@php_test$ find ./ -name 'test*' -depth -print
.//test.php
.//test1.php
.//test_2.php
.//test_global.php
.//testone/test1.txt
.//testone/test2.txt
.//testone
dingmac@php_test$ find ./ -name 'test*' -print
.//test.php
.//test1.php
.//test_2.php
.//test_global.php
.//testone
.//testone/test1.txt
.//testone/test2.txt
-d n 如果-d 后面直接跟参数就是指定层的满足条件的文件输出
demo
dingmac@php_test$ find ./ -name 'test*' -d 1 -print
.//test.php
.//test1.php
.//test_2.php
.//test_global.php
.//testone
dingmac@php_test$ find ./ -name 'test*' -d 2 -print
.//testone/test1.txt
.//testone/test2.txt
dingmac@php_test$ find ./ -name 'test*' -d 3 -print
dingmac@php_test$ find ./ -name 'test*' -d 4 -print
dingmac@php_test$ find ./ -name 'test*' -d 5 -print
.//testone/first/second/third/testwow.txt
再查看一个 mindepth 的例子 指定最少深度
dingmac@php_test$ find ./ -name 'test*' -mindepth 1 -print
.//test.php
.//test1.php
.//test_2.php
.//test_global.php
.//testone
.//testone/first/second/third/testwow.txt
.//testone/test1.txt
.//testone/test2.txt
dingmac@php_test$ find ./ -name 'test*' -mindepth 2 -print
.//testone/first/second/third/testwow.txt
.//testone/test1.txt
.//testone/test2.txt
dingmac@php_test$ find ./ -name 'test*' -mindepth 3 -print
.//testone/first/second/third/testwow.txt
参考 http://www.binarytides.com/linux-find-command-examples/ https://kb.iu.edu/d/admm
相同的可以使用-maxdepth 用来表示最大深度 demo find -name "*test* -maxdepth 2"
查找最深是2的文件
如果想取非,使用 ! 表示非 demo find -name "*test*"
查找文件中不包含 test 的文件
连字符 包含 -a -o ! 两个不带任何参数的时候默认是 “并”
-perm 补充
参考
http://www.cnblogs.com/gaojian/archive/2013/01/25/2876046.html
https://www.computerhope.com/unix/ufind.htm
我百度了一下 出现的各种帖子都是只给个例子 比如
find ./ -perm 666
这样的命令 就算把-perm 这个参数讲了 要不然就列几个例子 笼统的说明一下,更深的就没有了
所以下面在整理一下 -perm 这个参数的使用
mac 中 man find 找到 -perm 可以自己研究,mac是unix核和linux 优点差别
-perm 参数支持好几种方式
-
-perm mode 精确匹配 差一点都不行
可以使用数字表示和字符表示 demo:
find . -perm 642 ./timg.gif # 结果 find . -perm u=rw,g=r,o=w #和上面结果一样使用","连接 也是精确查找642
-
-perm -mode 包含就可以 比如 110 010 010 [622] 比如 有个文件的权限是 110 101 110 [656] 是无法被圈的 110 011 110 [634] 可以查找到
demo:
dingmac@linux_test$ ll total 8 drwxr-xr-x 5 dingmac staff 170B 9 13 18:38 ./ drwx------+ 37 dingmac staff 1.2K 9 17 22:37 ../ -rw-r-xrw- 1 dingmac staff 0B 9 13 17:23 file1.txt* -rw--wxr-- 1 dingmac staff 0B 9 13 17:23 file2.txt* -rwxr-xr-x 1 dingmac staff 44B 9 13 18:38 list_user.awk* dingmac@linux_test$ find . -perm 642 dingmac@linux_test$ find . -perm -642 ./file1.txt #如果要使用rwx 字符表示 和上面的一样 find ./ -perm -u=rw,g=r,o=w # 出来的结果和上面一样 # 注意的是只需要在 第一个上面加 - 就可以了 另外需要说明的是 -u=rw,g=r,o=w 这里面的 “=” 同样可以有+- 替代 = 表示含有 + 表示大于或者比这个高 其实和 = 没多大差别 - 表示低于都可以 其实 - 没有啥意义 理解上 = + 一个意思就可以了 所以 下面两个命令是一样的 dingmac@linux_test$ find ./ -perm -u+rw,g+x,o+rw .//file1.txt dingmac@linux_test$ find ./ -perm -u=rw,g=x,o=rw .//file1.txt
-perm +mode 其实是一个与或概念 1 xor 1 = 1 1 xor 0 = 0 0 xor 0 = 0
如果我们要查找 g 有写权限的文件 比如下面这个文件 将不被筛选 100 100 101 [445] 下面是例子
dingmac@linux_test$ ll
total 8
drwxr-xr-x 5 dingmac staff 170B 9 13 18:38 ./
drwx------+ 37 dingmac staff 1.2K 9 17 22:37 ../
-r--r--r-x 1 dingmac staff 0B 9 13 17:23 file1.txt*
-rw--wxr-- 1 dingmac staff 0B 9 13 17:23 file2.txt*
-rwxr-xr-x 1 dingmac staff 44B 9 13 18:38 list_user.awk*
dingmac@linux_test$ find . -perm +g=x
.
./file2.txt
./list_user.awk
dingmac@linux_test$ find . -perm +g+x
.
./file2.txt
./list_user.awk
linux 系统中还有一个 /mode 类似于 mac 中的 +
其他的就没啥
补充1
查找符合条件的文件,按照大小排序
需要用到命令有 find 还有sort 但是有一个问题想要获得 human readble 的方式显示就会有问题
demo 查看列表
dingmac@php_test$ find . -name "*test*" -type f -exec ls -al {} \; | sort -k 5 -nr
-rw-r--r-- 1 dingmac staff 18696 9 20 12:16 ./awk_test.txt
-rw-r--r--@ 1 dingmac staff 1038 9 19 17:40 ./test_2.php
-rw-r--r--@ 1 dingmac staff 407 9 19 15:59 ./test.php
-rw-r--r-- 1 dingmac staff 272 9 14 15:20 ./test1.php
-rw-r--r-- 1 dingmac staff 77 9 18 14:05 ./test_global.php
-rw-r--r-- 1 dingmac staff 0 9 20 23:05 ./testone/first/second/third/testwow.txt
-rw-r--r-- 1 dingmac staff 0 9 20 22:01 ./testone/test2.txt
-rw-r--r-- 1 dingmac staff 0 9 20 22:01 ./testone/test1.txt
但是想看到human readable的形式就不能按照上面的方法
我尝试过下面的方法 我发现ls 命令中有一个参数 -S 是按照size 倒序排列的
demo
dingmac@php_test$ ls -alShd test*
-rw-r--r--@ 1 dingmac staff 1.0K 9 19 17:40 test_2.php
-rw-r--r--@ 1 dingmac staff 407B 9 19 15:59 test.php
-rw-r--r-- 1 dingmac staff 272B 9 14 15:20 test1.php
drwxr-xr-x 6 dingmac staff 204B 9 20 23:05 testone
-rw-r--r-- 1 dingmac staff 77B 9 18 14:05 test_global.php
是ok的 -d 的命令是将文档当做文件处理 不循环列出下面的文件
但是在find命令 中使用的时候会有问题下面是demo
dingmac@php_test$ find . -name "*test*" -type f -exec ls -alSh {} \;
-rw-r--r-- 1 dingmac staff 18K 9 20 12:16 ./awk_test.txt
-rw-r--r--@ 1 dingmac staff 407B 9 19 15:59 ./test.php
-rw-r--r-- 1 dingmac staff 272B 9 14 15:20 ./test1.php
-rw-r--r--@ 1 dingmac staff 1.0K 9 19 17:40 ./test_2.php
-rw-r--r-- 1 dingmac staff 77B 9 18 14:05 ./test_global.php
-rw-r--r-- 1 dingmac staff 0B 9 20 23:05 ./testone/first/second/third/testwow.txt
-rw-r--r-- 1 dingmac staff 0B 9 20 22:01 ./testone/test1.txt
-rw-r--r-- 1 dingmac staff 0B 9 20 22:01 ./testone/test2.txt
上面就完全出错误了
暂时没有找到合适的方法
找到一个 可行版本 https://askubuntu.com/questions/80244/how-do-i-sort-by-human-readable-sizes-numerically
但要自己写
终于找到了方法 下面是demo
dingmac@php_test$ find . -type f -name "*test*" -exec ls -lShr {} \+
-rw-r--r-- 1 dingmac staff 0B 9 20 22:01 ./testone/test2.txt
-rw-r--r-- 1 dingmac staff 0B 9 20 22:01 ./testone/test1.txt
-rw-r--r-- 1 dingmac staff 0B 9 20 23:05 ./testone/first/second/third/testwow.txt
-rw-r--r-- 1 dingmac staff 77B 9 18 14:05 ./test_global.php
-rw-r--r-- 1 dingmac staff 272B 9 14 15:20 ./test1.php
-rw-r--r--@ 1 dingmac staff 407B 9 19 15:59 ./test.php
-rw-r--r--@ 1 dingmac staff 1.0K 9 19 17:40 ./test_2.php
-rw-r--r-- 1 dingmac staff 18K 9 20 12:16 ./awk_test.txt
关键是 “+”