find命令详解
来源:互联网 发布:2016免费顶级域名注册 编辑:程序博客网 时间:2024/05/18 00:21
一 简介
find命令用法格式:
find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
其中 [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec]对于有些老的版本并不支持,比如busybox就不支持这些选项,这些选项必须放在path之前。
[-H] [-L] [-P]主要控制碰到符号链接时采取的行为:
-P:也就是默认行为, 从来不follow symbolic links.
-L: 总是follow symbolic links.
-H: 仅仅当作为命令行参数时,也就是这里的[path...],才会follow symbolic links.
[-Olevel]:指定优化等级,在不影响测试结果的前提下,通过reorder测试test,加快测试速度, 0优化等级最低,这是默认行为,3优化等级最高,耗时最少的放在最前面,耗时最多的放在最后面。
[-D help|tree|search|stat|rates|opt|exec]:打印诊断信息,当查找的结果跟预想的不一致时,可以使用该调试选项。
[path...]至少有一个path在[expression]之前,如果没有指定,则默认为当前路径
[expression]由operators, options, tests, and actions构成,其中:
operators选项有:
( EXPR ): 括号优先操作
! EXPR -not EXPR: 非操作
EXPR1 -a EXPR2 EXPR1 -and EXPR2: 与操作
EXPR1 -o EXPR2 EXPR1 -or EXPR2 :或操作
EXPR1 , EXPR2:逗号表达式,EXPR1和EXPR2都会计算,但是EXPR1的值会被丢弃,整个逗号表达式的值等于EXPR2的值,逗号表达式对于搜索不同类型的文件特别有用,因为只需遍历整个目录一次,例如:
find / \( −perm −4000 −fprintf /root/suid.txt '%#m %u %p\n' \) , \
\( −size +100M −fprintf /root/big.txt '%−10s %p\n' \)
如果缺失,默认为与操作,即 EXPR1 EXPR2等价于 EXPR1 -a EXPR2
options选项有:
-d A synonym for -depth, for compatibility with FreeBSD, NetBSD, MacOS X and OpenBSD.
-daystart
Measure times (for -amin, -atime, -cmin, -ctime, -mmin, and -mtime) from the beginning of today rather than
from 24 hours ago. This option only affects tests which appear later on the command line.
-depth Process each directory's contents before the directory itself. The -delete action also implies -depth.
-follow
Deprecated; use the -L option instead.
--help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf
--version -xdev -ignore_readdir_race -noignore_readdir_race
必须放在test和action之前,它们是全局性的,会影响到后面test的结果。
test选项有:
-amin N -anewer FILE -atime N -cmin N
-cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME
-ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN
-links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE
-nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN
-readable -writable -executable
-wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N
-used N -user NAME -xtype [bcdpfls]
N can be +N or -N or N,返回结果true or false,如果单个test测试的结果为false,则同组中的后面test不会再进行测试,整组的测试结果为false
action选项有:
-delete -print0 -printf FORMAT -fprintf FILE FORMAT -print
-fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit
-exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;
-execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND
具有副作用,返回结果true or false,如果expression中除了prune外没有其他的action,则默认采用print.
find命令man手册:https://man.cx/find
二 源码实现
这里以busybox源码进行分析,其他版本实现可能存在差异。
- 选项解析
参数解析代码主要为static action*** parse_params(char **argv)这个函数,选项并不一定以“-”开头,比如括号操作,非操作,选项之间以空白字符进行分割:
- 与或非操作
部分代码如下所示:
/* Operators */
else if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) {
dbg("%d", __LINE__);
/* no further special handling required */
}
else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) {
dbg("%d", __LINE__);
/* start new OR group */
cur_group++;
appp = xrealloc(appp, (cur_group+2) * sizeof(*appp));
/*appp[cur_group] = NULL; - already NULL */
appp[cur_group+1] = NULL;
cur_action = 0;
}
#if ENABLE_FEATURE_FIND_NOT
else if (parm == PARM_char_not IF_DESKTOP(|| parm == PARM_not)) {
/* also handles "find ! ! -name 'foo*'" */
invert_flag ^= 1;
dbg("invert_flag:%d", invert_flag);
}
#endif
红色部分为一个group,蓝色为另一个group,group之间为或关系,group内部为与关系,invert为非操作标志。整个测试过程为:遍历path指定的目录,对每个文件进行test测试,当一个group测试所有的test全部为true时,整个表达式为true,不必进行下一group的测试,当group中碰到test为false时,group测试结果为false,测试下一group,如果所有group测试均为false,则整个表达式结果为false,这部分代码为:
static int exec_actions(action ***appp, const char *fileName, const struct stat *statbuf)
{
int cur_group;
int cur_action;
int rc = 0;
action **app, *ap;
/* "action group" is a set of actions ANDed together.
* groups are ORed together.
* We simply evaluate each group until we find one in which all actions
* succeed. */
cur_group = -1;
while ((app = appp[++cur_group]) != NULL) {
rc &= ~TRUE; /* 'success' so far, clear TRUE bit */
cur_action = -1;
while (1) {
ap = app[++cur_action];
if (!ap) /* all actions in group were successful */
return rc ^ TRUE; /* restore TRUE bit */
rc |= TRUE ^ ap->f(fileName, statbuf, ap);
#if ENABLE_FEATURE_FIND_NOT
if (ap->invert) rc ^= TRUE;
#endif
dbg("grp %d action %d rc:0x%x", cur_group, cur_action, rc);
if (rc & TRUE) /* current group failed, try next */
break;
}
}
dbg("returning:0x%x", rc ^ TRUE);
return rc ^ TRUE; /* restore TRUE bit */
}
- 括号操作
括号操作,代码实现部分如下:
else if (parm == PARM_char_brace) {
action_paren *ap;
char **endarg;
unsigned nested = 1;
dbg("%d", __LINE__);
endarg = argv;
while (1) {
if (!*++endarg)
bb_error_msg_and_die("unpaired '('");
if (LONE_CHAR(*endarg, '('))
nested++;
else if (LONE_CHAR(*endarg, ')') && !--nested) {
*endarg = NULL;
break;
}
}
ap = ALLOC_ACTION(paren);
ap->subexpr = parse_params(argv + 1);
*endarg = (char*) ")"; /* restore NULLed parameter */
argv = endarg;
}
通过代码可以看出,括号操作主要是通过嵌套递归操作实现的,括号操作数据结构如下,其中黄色部分为括号里的内容:
- -depth选项
- test和action区别
test和action之间有啥区别?
它们在表达式中出现的顺序有要求么,或者说test和action可以混合出现么?
每个group都需要action么,默认action print是指每个group还是整个表达式?
action的副作用是什么意思?
这是本人在阅读源代码之前心中的一些疑问,下面结合代码一一进行解答,首先贴出部分代码:
/* Actions */
else if (parm == PARM_print) {
dbg("%d", __LINE__);
G.need_print = 0;
(void) ALLOC_ACTION(print);
}
#if ENABLE_FEATURE_FIND_PRUNE
else if (parm == PARM_prune) {
dbg("%d", __LINE__);
(void) ALLOC_ACTION(prune);
}
#endif
else if (parm == PARM_name || parm == PARM_iname) {
action_name *ap;
dbg("%d", __LINE__);
ap = ALLOC_ACTION(name);
ap->pattern = arg1;
ap->iname = (parm == PARM_iname);
}
从上述代码可以看出,test和action没有本质的差别,都是一个action,只是action会设置G.need_print = 0而已,同时也可以回答第二个问题:test和action在表达式中的位置可以混合出现
关于第三个问题,通过上述代码片段其实也可以得到答案:既然test和action没有差别,那么每个group就不必非要有action。另外G.need_print 是全局的,只有一个,所有group共用,所以指的是整个表达式中,除了prune外没有指定其他的action,则默认为print:
fileAction()
{
............
r = exec_actions(G.actions, fileName, statbuf);
/* Had no explicit -print[0] or -exec? then print */
if ((r & TRUE) && G.need_print)
puts(fileName);
............
}
正是因为如此,find . −name afile −o −name bfile −print这条命令从来都不会打印afile文件名,即使在文件在当前目录下存在。
至于action的副作用,所以请看下面这条命令:
find ./ -name "*.o" -delete -type f
假如delete前面的test都为true,那么执行delete删除文件,则delete之后的test会因为文件被删除而报错。
三 注意事项
- 防止shell扩展
- 特殊文件名的处理
{
printf("%s%c", fileName, '\0');
return TRUE;
}
- Find命令使用详解
- Linux find命令详解
- UNIX find命令详解
- z find 命令详解
- find命令详解
- Linux find命令详解
- Linux find命令详解
- Linux find命令详解
- find命令详解
- Linux find命令详解
- Find 命令详解
- find命令详解
- find命令详解
- Linux find命令详解
- Linux find命令详解
- linux find命令详解
- find命令详解
- Linux命令FIND详解
- PSTN
- 老实人的代价·《一个勺子》
- C语言无符号整型的输出
- EditText限制输入类型
- 使用 Flask 设计 RESTful 的认证
- find命令详解
- Derby的jar说明
- csdn有用以及打算学习实践的技术和资源
- maven pom.xml设置jdk编译版本为1.8
- 整机调试连不上手机时解决办法
- 时间:UTC时间、GMT时间、本地时间、Unix时间戳
- 金钱格式化
- Dcokerfile构建Centos-ssh镜像
- GITLAB修改分支权限