我希望到grep中的所有关键字.h
和.c
文件的当前目录下./
,但不包括两个目录./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
.我的问题是:find命令的选项有从左到右的执行顺序?
有没有更简洁的方法来实现我的目标:grep一个关键字在所有.h
和.c
当前目录下的文件,但排除两个目录?
Jonathan Lef.. 6
该-o
运营商是"或"操作.在-o
第二路径后后它需要另一个测试.括号表达式经受的条件-type d
和-prune
太.总的来说,该术语表示'如果当前名称是目录,并且路径与路径表达式匹配,那么搜索将被修剪',这意味着搜索不会继续
一般操作find
是它搜索目录列表,并对搜索表达式求值为true的目录下找到的每个名称执行某些操作.
您当前的命令是:
find . -type d \( -path "./stubdom/*" -o -path "./dist/*" \) -prune -o -regex '.*\.\(h\|c\)$' -print
我要放弃这find .
部分,假设其余的答案.我还打算使用的名称A
和B
到位的stubdom
,并dist
缩短它使一切都可见.
我们可以通过更换肯定简化它-regex
具有-name
:
-type d \( -path "./A/*" -o -path "./B/*" \) -prune -o -name '*.[ch]' -print
请注意,条件之间的默认连接是'和'.使用C或壳符号&&
和||
,我们可以看到的是,表达的形式为:
(-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的话,那么你也可以使用-print0
术语in find
和-0
选项来解决这个xargs
问题; Mac OS X也是如此,因此也可能是其他BSD变体).
(使用系统(BSD)在Mac OS X 10.9.1上进行测试find
,而不是使用GNU进行测试find
.)
该-o
运营商是"或"操作.在-o
第二路径后后它需要另一个测试.括号表达式经受的条件-type d
和-prune
太.总的来说,该术语表示'如果当前名称是目录,并且路径与路径表达式匹配,那么搜索将被修剪',这意味着搜索不会继续
一般操作find
是它搜索目录列表,并对搜索表达式求值为true的目录下找到的每个名称执行某些操作.
您当前的命令是:
find . -type d \( -path "./stubdom/*" -o -path "./dist/*" \) -prune -o -regex '.*\.\(h\|c\)$' -print
我要放弃这find .
部分,假设其余的答案.我还打算使用的名称A
和B
到位的stubdom
,并dist
缩短它使一切都可见.
我们可以通过更换肯定简化它-regex
具有-name
:
-type d \( -path "./A/*" -o -path "./B/*" \) -prune -o -name '*.[ch]' -print
请注意,条件之间的默认连接是'和'.使用C或壳符号&&
和||
,我们可以看到的是,表达的形式为:
(-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的话,那么你也可以使用-print0
术语in find
和-0
选项来解决这个xargs
问题; Mac OS X也是如此,因此也可能是其他BSD变体).
(使用系统(BSD)在Mac OS X 10.9.1上进行测试find
,而不是使用GNU进行测试find
.)