处理此 xargs 多重命令中的括号

处理此 xargs 多重命令中的括号

我怀疑以下问题已经得到解答,但我不知道该问题的术语,我已经足够好找到现有的答案。

我正在编写一个命令来遍历文件列表并在每行输出文件名,后跟以 P 开头的行数。到目前为止我已经得到了:

find -type f | xargs -I % sh -c '{ echo %; grep -P "^P \d+" % | wc -l; }  | tr "\n" ","; echo ""; '

(实际的 find 命令有点复杂,但简单来说,它在我运行此命令的目录树中找到大约 11k 个感兴趣的文件)

这个命令大约 98% 可以满足我的目的,但我发现有一小部分文件的名称中带有括号,我无法忽略它们或用其他内容永久替换括号。

结果我收到了一些这样的案例:

sh: -c: line 0: syntax error near unexpected token `('

我知道括号是 shell 特殊字符,因此例如,如果我直接在名称中带有括号的单个文件上运行 grep,则必须将文件名括在单引号中或转义括号。我尝试交换命令中的引号类型(最外层为双引号,内层为单引号),这样我就可以将 grep 调用中的“%”放在单引号中,但这没有帮助。

有没有办法处理find -> xargs -> sh链中的括号,以便它们在 sh 调用中得到正确处理?

答案1

最好不要将数据(文件名)直接嵌入代码(shell scriptlet)中。而是将文件名作为参数传递给您xargs运行的 shell:

find -type f | xargs -I % \
  sh -c '{ echo "$1"; grep -c -P "^P \d+" "$1"; } | tr "\n" ","; echo' sh %

此外,您应该能够使用grep -c代替grep | wc -l,它至少使命令更短一些。

答案2

由于您省略了.in find . -type f,我想您find是 GNU find,那么您可以执行以下操作:

find . -type f -printf %p, -exec grep -cP '^P \d' {} ';'

如果文件路径不包含:字符,您也可以这样做(使用 GNU grep):

grep -rcP '^P \d' . | tr : ,

如果它们可能包含:字符但不包含换行符,则可以通过仅替换:行中的最后一个来解决此问题,

grep -rcP '^P \d' . | LC_ALL=C sed 's/\(.*\):/\1,/'

该方法还可以用于:

find ... -type f -exec grep -cHP '^P \d' {} + | ...

如果您仍然需要使用find,例如因为您有更多选择标准。

答案3

ilkkachu 的回答看起来是一个很好的改进,可能就是你应该做的。

出于信息目的,添加更轻的触摸修复以显示问题所在:

find -type f | xargs -I % sh -c '{ echo "%"; grep -P "^P \d+" "%" | wc -l; }  | tr "\n" ","; echo ""; '

基本上 - 引用%将被替换的内容。

相关内容