我想在当前目录.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的操作,但是它如何工作?以及为什么它不是\( -path "./stubdom/*" -o -path "./dist/*" -o \)(我在末尾添加了另一个-o)。
  • 如果我将-regex放在-type之前,它将打印出.o文件,这意味着如果将-regex放在-type之前,则.h不起作用。
    我的问题是:
    find命令的选项的执行顺序是从左到右?
  • 是否有更整洁的方法来实现我的目标:grep在当前目录下的所有.c和ojit_code文件中使用关键字,但排除两个目录?
  • 最佳答案

  • -o运算符是“或”运算符。第二条路径之后的-o在它之后需要另一个测试。带括号的表达式也受-type d-prune条件的约束。总体而言,该术语表示“如果当前名称是目录,并且如果路径与任何路径表达式匹配,那么将修剪搜索”,这意味着搜索不会继续
  • find的一般操作是搜索目录列表,并对在搜索表达式计算为true的目录下找到的每个名称执行某些操作。

    您当前的命令是:
    find . -type d \( -path "./stubdom/*" -o -path "./dist/*" \) -prune -o -regex '.*\.\(h\|c\)$' -print
    

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

    我们当然可以通过将-regex替换为-name来简化它:
    -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个名称是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术语和-0xargs选项来解决此问题,如果您的这些命令的版本支持该表示法(GNU会支持该表示法,那么Mac OS X也是如此,因此也可能支持其他BSD变体)。

    (在Mac OS X 10.9.1上使用系统(BSD)find进行了测试,而不是使用GNU find进行了测试。)

    关于regex - grep当前目录下所有.h和.c文件中的关键字,但排除两个目录,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20871845/

    10-12 22:28
    查看更多