bash find 的 -print0 和 xargs 的 -0 开关是否有等价的 grep?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15976570/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 05:10:45  来源:igfitidea点击:

Is there a grep equivalent for find's -print0 and xargs's -0 switches?

bashunixgrepfindxargs

提问by Andrew Ferrier

I often want to write commands like this (in zsh, if it's relevant):

我经常想写这样的命令(在 中zsh,如果相关的话):

find <somebasedirectory> | \
    grep stringinfilenamesIwant | \
    grep -v stringinfilesnamesIdont | \
    xargs dosomecommand

(or more complex combinations of greps)

(或更复杂的 grep 组合)

In recent years findhas added the -print0switch, and xargs has added -0, which allow handling of files with spaces in the name in an elegant way by null-terminating filenames instead, allowing for this:

近年来find添加了-print0开关,xargs 也添加了-0,它允许通过空终止文件名以优雅的方式处理名称中带有空格的文件,允许这样做:

find <somebasedirectory> -print0 | xargs -0 dosomecommand

However, grep(at least the version I have, GNU grep 2.10 on Ubuntu), doesn't seem to have an equivalent to consume andgenerate null-terminated lines; it has --null, but that only seems related to using -lto output names when searching in files directly with grep.

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

Is there an equivalent option or combination of options I can use with grep? Alternatively, is there an easy and elegant way to express my pipe of commands simply using find's -regex, or perhaps Perl?

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

回答by Todd A. Jacobs

Use GNU Grep's --nullFlag

使用 GNU Grep 的--null标志

According to the GNU Grep documentation, you can use Output Line Prefix Control to handle ASCII NUL characters the same way as findand xargs.

根据GNU Grep 文档,您可以使用输出行前缀控制以与findxargs相同的方式处理 ASCII NUL 字符。

-Z
--null
Output a zero byte (the ASCII NUL character) instead of the character that normally follows a file name. For example, ‘grep -lZ' outputs a zero byte after each file name instead of the usual newline. This option makes the output unambiguous, even in the presence of file names containing unusual characters like newlines. This option can be used with commands like ‘find -print0', ‘perl -0', ‘sort -z', and ‘xargs -0' to process arbitrary file names, even those that contain newline characters.

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

Use trfrom GNU Coreutils

tr从 GNU Coreutils使用

As the OP correctly points out, this flag is most useful when handling filenames on input or output. In order to actually convert grep output to use NUL characters as line endings, you'd need to use a tool like sedor trto transform each line of output. For example:

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

find /etc/passwd -print0 |
    xargs -0 egrep -Z 'root|www' |
    tr "\n" "
find <somebasedirectory> -regex ".*stringinfilenamesIwant.*" ! -regex ".*stringinfilesnamesIdont.*" -exec dosomecommand {} + 
" | xargs -0 -n1

This pipeline will use NULs to separate filenames from find, and then convert newlines to NULs in the strings returned by egrep. This will pass NUL-terminated strings to the next command in the pipeline, which in this case is just xargsturning the output back into normal strings, but it could be anything you want.

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

回答by jlliagre

As you are already using GNU findyou can use its internal regular expression pattern matching capabilities instead of these grep, eg:

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

find <somebasedirectory> -print0 | \
 grep -z stringinfilenamesIwant | \
 grep -zv stringinfilesnamesIdont | \
 xargs -0 dosomecommand

回答by Chiel ten Brinke

The newest version of the GNU grep source can now use -z/--nullto separate the output by null characters, while it previously only worked in conjunction with -l:

最新版本的 GNU grep 源代码现在可以使用-z/--null将输出分隔为空字符,而以前它只能与-l

http://git.savannah.gnu.org/cgit/grep.git/commit/?id=cce2fd5520bba35cf9b264de2f1b6131304f19d2

http://git.savannah.gnu.org/cgit/grep.git/commit/?id=cce2fd5520bba35cf9b264de2f1b6131304f19d2

This means that your issue is solved automatically when using the newest version.

这意味着您的问题在使用最新版本时会自动解决。

回答by jarno

Use

find ./ -type f -exec bash -c 'grep "$@" | grep -v something | xargs dosomething' -- {} +

However, the pattern may not contain newline, see bug report.

但是,模式可能不包含换行符,请参阅错误报告

回答by jordanm

Instead of using a pipe, you can use find's -execwith the +terminator. To chain multiple commands together, you can spawn a shell in -exec.

您可以将 find-exec+终止符一起使用,而不是使用管道。要将多个命令链接在一起,您可以在-exec.

find <somebasedirectory> -print0 | xargs -0 -I % grep something '%'

回答by Vadim Rudkov

##代码##