find是unix/linux命令行工具箱中最棒的工具之一。
1、find命令的工作方式如下:沿着文件层次结构向下遍历,匹配符合条件的文件,执行相应的操作。
2、要列出当前目录及子目录下所有的文件和文件夹:
$find base_path
base_path可以放在任意位置,find会从该位置开始向下查找。如
$find . -print
#打印文件和目录的列表
-print指明打印出匹配文件的文件名(路径)。当使用-print时,‘\n‘作为用于对输出的文件名进行分隔。就算忽略-print,find命令仍会打印出文件名。
-print0指明使用‘\0‘作为匹配的文件名之间的定界符,当文件名中包含换行符这个方法就有用了。
3、补充内容
a、根据文件名或正则表达式进行搜索
选项-name的参数指定了文件名所必须匹配的字符串。可以将通配符作为参数使用。*.txt能够匹配所有以.txt结尾的文件名。选项-print在终端中打印出符合条件(如-name)的文件名或文件路径。如
$find /home/slynux -name "*.txt" -print
find命令有一个选项-iname(忽略字符大小写)。
如果想匹配多个条件中的一个,则可以采用OR条件操作:
$ls
new.txt some.jpg text.pdf
$find . \(-name "*.txt" -o - name "*.pdf" \) -print
./text.pdf
./new.txt
上面的代码会打印出所有的.txt和.pdf文件,是因为这个find命令能够匹配所有这两类文件。\(以及\)用于将-name "*.txt" -o -name "*.pdf"视为一个整体。
选项-path的参数可以使用通配符来匹配文件路径。-name总是用给定的文件名进行匹配。-path则将文件路径作为一个整体进行匹配。如
$find /home/users -path "*/slynux/*" -print
这会匹配以下路径:
/home/users/list/slynux.txt
/home/users/slynux/eg.css
选项-regex的参数和-path的类似,只不过-regex是基于正则表达式来匹配文件路径的。
正则表达式是通配符匹配的最高级形式,它可以指定文本模式。我们借助这种模式来匹配文本及进行打印。使用正则表达式进行文本匹配的一个典型例子就是从一堆文本中解析所有的E-mail地址。E-mail地址通常采用[email protected]这种形式,所以可以将其一般化为[a-z0-9][email protected][a-z0-9]+.[a-z0-9]+。符号+指明在它之前的字符类中的字符可以出现一次或多次。
下面的命令匹配.py或.sh文件
$ls
new.py next.jpg test.py
$find . -regex ".*\(\.py\|\.sh\)$"
类似的,-iregex可以让正则表达式忽略大小写。
b、否定参数
find也可以用“!”否定参数的含义。如
$find . ! -name "*.txt" -print
上面的命令能够匹配所有不以.txt结尾的文件名。
c、基于目录深度的搜索
find命令在使用时会遍历所有的子目录。可以采用深度选项-maxdepth和-mindepth来限制find命令遍历的目录深度。
当使用find在当前目录中查找,使用深度设置为1;向下两级时,使用深度可以设置为2,以此类推。
注意:-maxdepth和-mindepth应该作为find的第三个参数出现。
d、根据文件类型搜索
文件具有不同的类型,如普通文件(f)、目录(d)、字符设备(c)、块设备(d)、符号链接(l)、硬链接、套接字(s)以及FIFO(p)等。
-type可以对文件搜索进行过滤。如
$find . -type d -print #只列出所有目录
$find . -type f -print #只列出所有文件
$find .-type l -print #只列出符号链接
e、根据文件时间进行搜索
unix/linux文件系统中的每一个文件都有三种时间戳,如下
访问时间(-atime):用户最近一次访问文件的时间
修改时间(-mtime):文件内容最后一次被修改的时间。
变化时间(-ctime):文件元数据(例如权限或所有权)最后一次改变的时间。
在unix中并没有所谓的“创建时间”的概念。
-atime,-mtime,-ctime可作为find的时间选项。他们可以用整数值指定,单位是天。这些整数值通常还带有-或+:-表示小于,+表示大于。
如:打印出在最近7天内被访问过的所有文件:
$find . -type f -atime -7 -print
打印出恰好在7天前被访问过的所有文件
$find . -type f -atime 7 -print
同理,超过的时候就使用+7.
还有一些基于时间的参数,但其单位是分钟。
-amin(访问时间)
-mmin(修改时间)
-cmin(变化时间)
eg:$ find . -type f -amin +7 -print#打印出访问时间超过7分钟的所有文件。
使用-newer,可以指定一个用于比较时间戳的参考文件,然后找出比参考文件更新的(更近的修改时间)所有文件。
如:找出比file.txt修改时间更近的所有文件
$find . -type f -newer file.txt -print
这个选项对编写系统备份和维护脚本很有帮助。
f、基于文件大小的搜索
$find . -type f -size +2k #大于2KB的文件
$finid . -type f -size -2k #小于2KB的文件
$finid . -type f -size 2k #等于2KB的文件
·除了k之外还有,b(块:512字节),c(字节),w(字:2字节),k(1024字节),M(1024k字节),G(1024M字节)。
g、删除匹配的文件
-delete可以用来删除find查找到的匹配文件
$find . -type f -name "*.swp" -delete
h、基于文件权限和所有权的匹配
列出具有特定权限的所有文件:
$find . -type f -perm 644 -print#打印出权限为644的文件
-perm指明find应该只匹配具有特定权限值的文件。
如:找到那些没有设置好执行权限的PHP文件:
$ find . -type f -name "*.php ! -perm 644 -print"
也可以根据文件的所有权进行搜索。用选项-user USER就能够找出由某个特定用户所拥有的文件。
参数USER可以是用户名或UID。
例如,打印出用户slynux拥有的所有文件
$ find . -type f -user slynux -print
i、利用find执行命令或动作
find命令可以借助选项-exec与其他命令进行结合。-exec算得上是find最强大的特性之一。
注意:必须以root用户的身份执行命令才能够进行所有权的更改。
#find . -type f -user root -exec chown slynux {} \;#将root用户的文件所有权更改成另一位用户
在这个命令中,{}是一个与exec选项搭配使用的特殊字符串。对于每一个匹配的文件,{}会被替换成相应的文件名。如:find命令找到两个文件test1.txt和test2.txt,其所有者均为slynux,那么find就会执行;
chown slynux{}
它会被解析为chown slynux test1.txt和chown slynux test2.txt
有时候我们并不希望对每个文件都执行一次命令。我们更希望使用文件列表作为命令参数,这样就可以少运行几次命令了。如果是这样,可以在exec中使用+来代替。
将给定目录中的所有c程序文件拼接起来写入单个文件all_c_files.txt,可以使用find找到所有的c文件,然后结合-exec使用cat命令
$find . -type f -name "*.c" -exec cat {} \; >all_c_files.txt
-exec之后可以接任何命令。{}表示一个匹配。对于任何匹配的文件名,{}均会被该文件名所替换。上面使用>作为重定向操作符,而>>表示重定向追加的意思。当有多个数据流被追加到单个文件中时才有必要使用>>。
$find . -type f -mtime +10 -name "*.txt" -exec cp {} OLD \;#将10天前的.txt文件复制到OLD目录中。
注意:-exec结合多个命令,我们无法再-exec参数中直接使用多个命令。它只能够接受单个命令,不过可以把多个命令写到一个shell脚本,然后在-exec中使用这个脚本:-exec ./commands.sh {} \;
-exec能够同printf结合来生成有用的输出信息,eg
$find . -type f -name "*.txt" -exec printf "Text file :%s\n" {} \;
j.让findt跳过特定的目录
将某些文件或目录从搜索过程中排除在外的技巧被称为修剪。
$find devel/source_path \(-name ".git" -prune\) -o \(-type f -printf \)
以上命令打印出不包括在.git目录中的所有文件的名称(路径)。
\(-name ".git" -prune \)的作用是用于进行排除,它指明了.git目录应该被排除在外,而\(-type f -printf \)指明了需要执行的动作。