find
命令,递归地进入一个巨大的目录树,显示所有的.c、.cpp和.h文件,但省略包含某些子字符串的匹配项。最终,我希望将输出发送到xargs
命令上,对所有匹配的文件进行特定处理。我可以通过管道将find
的输出通过grep过滤以删除包含这些子字符串的匹配项,但对于包含空格的文件名,这种解决方法效果不佳。因此,我尝试使用find
的-print0选项,将每个文件名终止符改为一个nul字符而不是一个换行符(空格),并使用xargs -0
来期望接收nul分隔的输入而不是以空格分隔的输入,但我无法成功地将nul分隔的find
传递给管道grep过滤器;grep -Z在这方面似乎没有起到帮助作用。
所以我想写一个更好的find
regex,取消中间的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文件,但不包括出现在“generated”和“deploy”目录中的文件。
顺便说一下,你可以通过将整行复制并粘贴到你的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传输它的输出,'bam bam'文件将被视为两个单独的(不存在的)文件名(请注意,这里我只是使用ls
作为我的实际输出处理方式的替代品):
$ 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
使用find
和xargs
命令,我们可以通过添加-print0和-0参数来增强功能:
$ 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
这很好,但我不想在输出中包含“generated”和“deploy”目录。因此,我尝试了以下方法:
$ find . -regextype posix-egrep -regex ".+\.(c|cpp|h)$" -print0 | grep -v generated | grep -v deploy | xargs -0 -n 1 ls
barney fred
使用 grep 后发现它无法正常工作,随后我尝试使用 -Z 选项(并不确定该选项的确切作用),但是这个选项也无法解决问题。为此,我想自己编写一个更好的正则表达式来使用 find
命令,以下是我得到的最佳方案:
find . -regextype posix-egrep -regex "(?!.*(generated|deploy).*$)(.+\.(c|cpp|h)$)" -print0 | xargs -0 -n 1 ls
然而bash不接受这个命令(出现"!.*: event not found"错误),即使那不是问题,我的正则表达式在我通常使用的正则表达式测试网页上也不能正确工作。
你有什么想法可以让这个正则表达式正常工作吗?这是我想要的输出结果:
$ 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
……而我希望避免脚本和临时文件,这可能是我的唯一选择。
提前感谢! -Mark
bash
将!
解释为历史扩展请求。在包含该字符的字符串中使用单引号或进行额外转义。我建议使用单引号! - sorpigal