繁体   English   中英

grep当前目录下所有.h和.c文件中的关键字,但不包括两个目录

[英]grep a keyword in all .h and .c files under current directory but exclude two directories

我想在当前目录下的所有.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操作!)

但是,我不太明白为什么会这样。 我有几个问题:

  1. \\( -path "./stubdom/*" -o -path "./dist/*" \\)这是一个find的动作,但它是如何工作的? 为什么它不是\\( -path "./stubdom/*" -o -path "./dist/*" -o \\) (我在末尾添加了另一个-o)。

  2. 如果我把-regex的前-type ,它会打印出.o文件,这意味着你-regex如果它之前把不工作-type 我的问题是:find命令的选项有从左到右的执行顺序?

  3. 有没有更简洁的方法来实现我的目标:在当前目录下的所有.h.c文件中grep一个关键字,但排除两个目录?

  1. -o运算符是'或'运算符。 第二条路径之后的-o需要在它之后进行另一次测试。 带括号的表达式也受条件-type d-prune约束。 总的来说,该术语表示'如果当前名称是目录,并且路径与路径表达式匹配,那么搜索将被修剪',这意味着搜索不会继续

  2. find的一般操作是它搜索目录列表,并对搜索表达式求值为true的目录下找到的每个名称执行某些操作。

    您当前的命令是:

     find . -type d \\( -path "./stubdom/*" -o -path "./dist/*" \\) -prune -o -regex '.*\\.\\(h\\|c\\)$' -print 

    我要放弃这个find . 部分,将其视为其余答案的假设。 我还将使用名称AB代替stubdomdist来缩短它,以便一切都可见。

    我们当然可以通过用-name替换-regex来简化它:

     -type d \\( -path "./A/*" -o -path "./B/*" \\) -prune -o -name '*.[ch]' -print 

    请注意,条件之间的默认连接是'和'。 使用C或shell表示法&&|| ,我们可以看到表达式的形式如下:

     (-type d && ( ... ) && -prune) || (-name '*.[ch]' && -print) 

    当您在-type之前移动-regex (现在为-name )时,将表达式重写为:

     (-name '*.[ch]' && -type d && ( ... ) && -prune) || (-print) 

    因此,出现目标文件名的原因是无条件地应用了打印。

  3. 我的实验表明, -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个名称是cd下的文件,这些是需要的文件。

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 {} +

如果任何文件名或目录名包含空格(或制表符或换行符),则可以避免出现问题。 您也可以解决,随着-print0足月find-0选项xargs ,如果您对这些命令的版本支持的符号(GNU做,也是如此的Mac OS X,因此可能是其他BSD变体也是如此)。

测试在Mac OS X 10.9.1完成与系统(BSD) find ,不与GNU find 。)

在这里,我会尽力回答你:

  1. 我不确定你为什么要在最后添加另一个-o 如果任何-path "./stubdom/*"-path "./dist/*" ,则行\\( -path "./stubdom/*" -o -path "./dist/*" \\)将被评估为True -path "./dist/*"将匹配。 -o是一个逻辑OR ,它是一个二元运算符,所以它需要两个参数。 如果没有别的,你不能在最后附加它。
  2. 你可能忘了移动-o 如果你没有在-type d-regex ...之间放置一个OR -regex ... find将只查找与regexp匹配的目录。 而不是任何目录匹配正则表达式的东西。 顺便说一句,是的,因为找到选项的顺序绝对相关。
  3. 我认为你的解决方案已经足够好了。

总结你的线如何工作,它等同于这个伪代码:

if(isdir(file) and file != "./stubdom/*" and file != "./dist/*")
    print file;
else if (regex(file, '.*\.\(h\|c\)$' and file != "./stubdom/*" and file != "./dist/*")
    print file;

编辑:

阅读我记得关于grep的--exclude-dir选项的评论。 试试吧。 它可能是更简洁的解决方案。

  1. \\( -path "./stubdom/*" -o -path "./dist/*" \\)-prune的过滤器,因此应排除这些目录。 它不能是\\( -path "./stubdom/*" -o -path "./dist/*" -o \\) ,这可能是一个错误。
  2. 如果你这样做, find实际搜索,所以匹配约束被丢弃。
  3. grep还有排除文件的选项(例如--exclude-dir等)。

您还可以尝试以下命令:

find | awk '(! (/stubdom\// || /dist\//)) && /\.(c|h)$/ {
    r=system ("grep -q map_foreign_range "$0)
    if(!r) print
}'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM