我想在当前目录 ./
下的所有 .h
和 .c
文件中 grep 一个关键字,但排除两个目录 ./stubdom
和 ./dist
在输出中。
我搜索、尝试和测试了几个命令;最后我认为一个 shell 可以工作:
find . -type d \( -path "./stubdom/*" -o -path "./dist/*" \) -prune -o -regex '.*\.\(h\|c\)$' -print | xargs grep map_foreign_range
此 shell 正在查找所有 .h 和 .c 文件并排除 ./stubdom/和 ./dist 路径:
find . -type d \( -path "./stubdom/*" -o -path "./dist/*" \) -prune -regex '.*\.\(h\|c\)$' -print | xargs grep map_foreign_range
但是,上面的命令不起作用!
(我删除了正则表达式之前的 -o 以获得 AND 操作!)
但是,我不太明白为什么会这样。我有几个问题:
\( -path "./stubdom/*"-o -path "./dist/*"\)
这是一个 find Action ,但它是如何工作的呢?以及为什么它不是\( -path "./stubdom/*"-o -path "./dist/*"-o\)
(我在末尾添加了另一个 -o)。如果我将
-regex
放在-type
之前,它将打印出 .o 文件,这意味着-regex
如果放在-type
之前将不起作用。 我的问题是: find命令的选项有从左到右的执行顺序?有没有更简洁的方法来实现我的目标:在当前目录下的所有
.h
和.c
文件中 grep 一个关键字,但排除两个目录?
最佳答案
-o
运算符是“或”运算符。第二条路径之后的-o
需要在它之后进行另一个测试。括号内的表达式也受制于条件-type d
和-prune
。总的来说,该术语表示“如果当前名称是一个目录,并且如果路径与任一路径表达式匹配,则搜索被删减”,这意味着搜索不会继续find
的一般操作是搜索目录列表,并对在搜索表达式计算结果为真的目录下找到的每个名称执行某些操作。您当前的命令是:
find . -type d \( -path "./stubdom/*" -o -path "./dist/*" \) -prune -o -regex '.*\.\(h\|c\)$' -print
我将删除
find .
部分,将其视为其余答案的假设。我还将使用名称A
和B
代替stubdom
和dist
来缩短它一切都是可见的。我们当然可以通过用
-name
替换-regex
来简化它:-type d \( -path "./A/*" -o -path "./B/*" \) -prune -o -name '*.[ch]' -print
请注意,条件之间的默认连接符是“和”。使用 C 或 shell 符号
&&
和||
,我们可以看到表达式的形式为:(-type d && ( ... ) && -prune) || (-name '*.[ch]' && -print)
当您将
-regex
(现在是-name
)移到-type
之前时,您将表达式重写为:(-name '*.[ch]' && -type d && ( ... ) && -prune) || (-print)
因此,目标文件名出现的原因是打印无条件应用。
我的实验表明
-path
项上的/*
会适得其反。
为了演示,创建一个垃圾目录,cd
进入它,然后运行:
mkdir a b c d
for d in a b c d
do
for file in abc def pqr zyz
do
for ext in c h
do cp /dev/null $d/$file.$ext
done
done
done
现在运行:
find . -name '*.[ch]' | wc -l
这给出了答案 32。
现在运行:
find . -type d \( -path "./a/*" -o -path "./b/*" \) -prune -o -name '*.[ch]' -print | wc -l
这也给出了 32。
删除 -path
操作数的 /*
部分,您得到 16。删除 wc
显示这 16 个名称是文件在 c
和 d
下,这是需要的。
find . -type d \( -path "./a" -o -path "./b" \) -prune -o -name '*.[ch]' -print
因此,应用于您的场景,您应该能够使用:
find . -type d \( -path "./stubdom" -o -path "./dist" \) -prune -o -name '*.[ch]' -print
但是,您最好避免 xargs
与:
find . -type d \( -path "./a" -o -path "./b" \) -prune -o -name '*.[ch]' \
-exec grep map_foreign_range {} +
如果任何文件名或目录名包含空格(或制表符或换行符),这可以避免出现问题。如果您的这些命令版本支持该表示法(GNU 支持;Mac OS X 支持,因此其他 BSD 变体也支持)。
(使用系统 (BSD) find
在 Mac OS X 10.9.1 上完成测试,而不是使用 GNU find
。) p>
关于regex - grep当前目录下所有.h和.c文件中的关键字但排除两个目录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20871845/