是否有找到-print0和xargs的-0开关的grep等价物?

And*_*ier 41 unix bash grep find xargs

我经常想写这样的命令(zsh如果它是相关的):

find <somebasedirectory> | \
    grep stringinfilenamesIwant | \
    grep -v stringinfilesnamesIdont | \
    xargs dosomecommand
Run Code Online (Sandbox Code Playgroud)

(或更复杂的greps组合)

近年来find添加了-print0交换机,并添加了xargs -0,它允许通过空终止文件名来优雅地处理名称中带有空格的文件,从而允许:

find <somebasedirectory> -print0 | xargs -0 dosomecommand
Run Code Online (Sandbox Code Playgroud)

但是,grep(至少我拥有的版本,Ubuntu上的GNU grep 2.10),似乎没有等效消耗生成以null结尾的行; 它有--null,但这似乎只与使用-lgrep直接搜索文件时输出名称有关.

我可以使用与grep相同的选项或选项组合吗?或者,是否有一种简单而优雅的方式来表达我的命令管道,只需使用find -regex或Perl?

Tod*_*obs 43

使用GNU Grep的--null标志

根据GNU Grep文档,您可以使用输出行前缀控件来处理ASCII NUL字符,方法与findxargs相同.

-Z
--null
输出零字节(ASCII NUL字符),而不是通常跟随文件名的字符.例如,'grep -lZ'在每个文件名后输出一个零字节,而不是通常的换行符.即使存在包含不常用字符(如换行符)的文件名,此选项也会使输出明确无误.此选项可与"find -print0","perl -0","sort -z"和"xargs -0"等命令一起使用,以处理任意文件名,甚至是包含换行符的文件名.

使用trGNU Coreutils

正如OP正确指出的那样,在处理输入或输出上的文件名时,此标志最有用.为了实际转换grep输出以使用NUL字符作为行结尾,您需要使用像sedtr这样的工具来转换每行输出.例如:

find /etc/passwd -print0 |
    xargs -0 egrep -Z 'root|www' |
    tr "\n" "\0" |
    xargs -0 -n1
Run Code Online (Sandbox Code Playgroud)

此管道将使用NUL将文件名与find分开,然后将换行符转换为egrep返回的字符串中的NUL.这会将NUL终止的字符串传递给管道中的下一个命令,在这种情况下只是xargs将输出转换回普通字符串,但它可能是你想要的任何东西.

  • 使用`-0`和`-z`开关的重点是文件名可能包含换行符.使用`tr`完全不使用开关. (4认同)
  • 嗯,我不确定这个.我刚刚写道,这个开关是不相关的(正如我在原始问题中提到的那样),因为手册页向我暗示,只有当与生成文件名的开关(例如`-l`)结合使用时,它才有意义.但是,一些初步的测试并不是那么清楚.需要更多调查.为过早的downvote道歉,我无法撤消. (3认同)
  • tr解决方案非常适合那些没有print0 like选项的命令。 (3认同)
  • 我不得不使用`--null-data`而不是`--null`。我不是100%知道为什么,但是从`grep --help`中可以看出,`--null-data`可能会改变grep的行为以使用null终止,而`--null`只会_output_ null-termination-处理_input_时不考虑它。 (2认同)

jll*_*gre 5

由于您已经在使用GNU find,因此可以使用其内部正则表达式模式匹配功能,而不是这些grep,例如:

find <somebasedirectory> -regex ".*stringinfilenamesIwant.*" ! -regex ".*stringinfilesnamesIdont.*" -exec dosomecommand {} + 
Run Code Online (Sandbox Code Playgroud)