2012-07-12 184 views
2

我想在Linux的find命令中使用正则表达式来递归地跳入一个庞大的目录树,向我展示所有的.c,.cpp和.h文件,但省略了包含某些子字符串的匹配。最终,我想将输出发送到一个xargs命令,以对所有匹配的文件执行特定处理。我可以通过grep管道输出find以删除包含这些子字符串的匹配项,但该解决方案对于包含空格的文件名不起作用。所以我尝试使用find的-print0选项,它终止每个文件名用一个nul字符而不是一个换行符(空白),并使用xargs -0来期望nul-delimited输入,而不是空格分隔的输入,但我无法弄清楚如何通过管道grep过滤器成功地通过nul-delimited find; grep -Z在这方面似乎没有帮助。如何从Linux的“find”命令的输出中排除匹配某些模式的目录?

所以我想我只是写一个更好的正则表达式为find,并取消中间grep过滤器...也许sed将是一个替代?

在任何情况下,对目录的以下的小采样...

./barney/generated/bam bam.h 
./barney/src/bam bam.cpp 
./barney/deploy/bam bam.h 
./barney/inc/bam bam.h 
./fred/generated/dino.h 
./fred/src/dino.cpp 
./fred/deploy/dino.h 
./fred/inc/dino.h 

...我要输出到包括所有的.H,.C,和.cpp文件,但不是那些那些出现在'生成'和'部署'目录中的。

顺便说一句,你可以通过切割&粘贴在此整条生产线到您的bash shell创建用于测试的解决方案,这个问题整个测试目录(名为fredbarney):

mkdir fredbarney; cd fredbarney; mkdir fred; cd fred; mkdir inc; mkdir docs; mkdir generated; mkdir deploy; mkdir src; echo x > inc/dino.h; echo x > docs/info.docx; echo x > generated/dino.h; echo x > deploy/dino.h; echo x > src/dino.cpp; cd ..; mkdir barney; cd barney; mkdir inc; mkdir docs; mkdir generated; mkdir deploy; mkdir src; echo x > 'inc/bam bam.h'; echo x > 'docs/info info.docx'; echo x > 'generated/bam bam.h'; echo x > 'deploy/bam bam.h'; echo x > 'src/bam bam.cpp'; cd ..; 

这个命令在所有的.H ,.C,和.cpp文件...

find . -regextype posix-egrep -regex ".+\.(c|cpp|h)$" 

...但如果我管其通过xargs的输出时,“咣当咣当”文件分别获得视为两个独立的(不存在的)的文件名(注意这里我只是简单地使用ls作为我交流的替身tually要与输出做):

$ find . -regextype posix-egrep -regex ".+\.(c|cpp|h)$" | xargs -n 1 ls 
ls: ./barney/generated/bam: No such file or directory 
ls: bam.h: No such file or directory 
ls: ./barney/src/bam: No such file or directory 
ls: bam.cpp: No such file or directory 
ls: ./barney/deploy/bam: No such file or directory 
ls: bam.h: No such file or directory 
ls: ./barney/inc/bam: No such file or directory 
ls: bam.h: No such file or directory 
./fred/generated/dino.h 
./fred/src/dino.cpp 
./fred/deploy/dino.h 
./fred/inc/dino.h 

所以我可以提高,与-print0和-0参数传递给findxargs

$ find . -regextype posix-egrep -regex ".+\.(c|cpp|h)$" -print0 | xargs -0 -n 1 ls 
./barney/generated/bam bam.h 
./barney/src/bam bam.cpp 
./barney/deploy/bam bam.h 
./barney/inc/bam bam.h 
./fred/generated/dino.h 
./fred/src/dino.cpp 
./fred/deploy/dino.h 
./fred/inc/dino.h 

...这是伟大的,但我不希望输出中的“生成”和“部署”目录。所以我试试这个:

$ find . -regextype posix-egrep -regex ".+\.(c|cpp|h)$" -print0 | grep -v generated | grep -v deploy | xargs -0 -n 1 ls 
barney fred 

......这显然不起作用。所以我尝试使用-Z选项和grep(不知道-Z选项到底是什么),那也不管用。所以,我想我会写一个更好的正则表达式find,这是我能想出的最好:

find . -regextype posix-egrep -regex "(?!.*(generated|deploy).*$)(.+\.(c|cpp|h)$)" -print0 | xargs -0 -n 1 ls 

...但庆典不喜欢这样(*:!未找到事件,无论这意味着),即使这不是一个问题,我的正则表达式似乎没有在我通常使用的正则表达式测试器网页上工作。

任何想法,我可以使这项工作?这是我想要的输出:

$ find . [----options here----] | [----maybe grep or sed----] | xargs -0 -n 1 ls 
./barney/src/bam bam.cpp 
./barney/inc/bam bam.h 
./fred/src/dino.cpp 
./fred/inc/dino.h 

...我想避免脚本&临时文件,我想可能是我唯一的选择。

在此先感谢! 马克

+2

'未找到事件'是因为'!'被解释为'bash'的历史扩展请求。单引号出现在其中的字符串,或给它一个额外的转义。我建议单引号! – Sorpigal 2012-07-12 16:27:47

回答

5

这个工作对我来说:

从您的版本
find . -regextype posix-egrep -regex '.+\.(c|cpp|h)$' -not -path '*/generated/*' \ 
     -not -path '*/deploy/*' -print0 | xargs -0 ls -L1d 

的变化是微乎其微的:我单独添加某些路径模式的排除,因为这是比较容易的,我的单引号的东西从外壳隐藏插值。

未找到该事件是因为!被解释为请求历史扩展bash。解决方法是使用单引号而不是双引号。

流行测验:sh中单引号字符串中的特殊字符是什么?

答:只有'是特殊的(它结束的字符串)。这是最终的安全。

grep-Z(有时也被称为--null)使得grep输出以空字符来代替新行终止。你想要的是-z(有时被称为--null-data),它导致grep将它的输入中的空字符解释为换行符而不是换行符。这使得它按预期工作,输出为find ... -print0,它在每个文件名后面添加一个空字符,而不是换行符。

如果你做了这种方式:

find . -regextype posix-egrep -regex '.+\.(c|cpp|h)$' -print0 | \ 
    grep -vzZ generated | grep -vzZ deploy | xargs -0 ls -1Ld 

然后输入grep输出会一直空分隔,它会正常工作......直到你的源文件中的一个开始被命名为deployment.cpp,并开始被你的脚本“神秘地”排除在外。

顺便提一句,下面是生成测试用例文件集的更好方法。

while read -r file ; do 
    mkdir -p "${file%/*}" 
    touch "$file" 
done <<'DATA' 
./barney/generated/bam bam.h 
./barney/src/bam bam.cpp 
./barney/deploy/bam bam.h 
./barney/inc/bam bam.h 
./fred/generated/dino.h 
./fred/src/dino.cpp 
./fred/deploy/dino.h 
./fred/inc/dino.h 
DATA 

因为我这样做无论如何,以验证我想我会分享并保存你重复。不要做任何事情两次!这就是电脑的用途。

+0

优秀!谢谢。 – phonetagger 2012-07-12 17:01:56

+0

特别感谢您为我解决问题的两种方式。 – phonetagger 2012-07-12 17:05:48

+0

+1非常彻底! – tripleee 2012-07-13 09:03:15

相关问题