Bash find'有grep等价物吗;s-print0和xargs';s-0开关?

Bash find'有grep等价物吗;s-print0和xargs';s-0开关?,bash,unix,grep,find,xargs,Bash,Unix,Grep,Find,Xargs,我经常想编写这样的命令(在zsh中,如果相关的话): 然而,grep(至少我有一个版本,Ubuntu上的GNU grep 2.10),似乎没有一个等价物来消耗和生成空终止行;它有--null,但这似乎只与直接使用grep在文件中搜索时使用-l输出名称有关 是否有一个等价的选项或选项组合可以与grep一起使用?或者,是否有一种简单而优雅的方式来表达我的命令管道,只需使用find的-regex,或者Perl?而不是使用管道,您可以使用find的-exec和+终止符。要将多个命令链接在一起,可以在-e

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

然而,
grep
(至少我有一个版本,Ubuntu上的GNU grep 2.10),似乎没有一个等价物来消耗和生成空终止行;它有
--null
,但这似乎只与直接使用grep在文件中搜索时使用
-l
输出名称有关


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

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

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

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

find <somebasedirectory> -regex ".*stringinfilenamesIwant.*" ! -regex ".*stringinfilesnamesIdont.*" -exec dosomecommand {} + 
find-regex.“*StringInfineNameSiwant.*”-正则表达式“*stringinfilesnamesIdont.*”-exec dosomecommand{}+
使用GNU Grep的
--null
标志 根据,可以使用输出行前缀控件以与find和xargs相同的方式处理ASCII NUL字符

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

使用GNU Coreutils中的
tr
正如OP正确指出的,在处理输入或输出文件名时,此标志最有用。为了实际转换grep输出以使用NUL字符作为行结束符,您需要使用sed或tr之类的工具来转换输出的每一行。例如:

find /etc/passwd -print0 |
    xargs -0 egrep -Z 'root|www' |
    tr "\n" "\0" |
    xargs -0 -n1
此管道将使用NULs将文件名与find分开,然后在egrep返回的字符串中将换行符转换为NULs。这将把NUL终止的字符串传递给管道中的下一个命令,在本例中,这只是xargs将输出转换回普通字符串,但它可以是您想要的任何字符串。

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

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

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

使用

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

但是,模式可能不包含换行符,请参见。

这会为find找到的每个文件生成一个新的bash shell吗?我无法从find手册页中看出…@AndrewFerrier-no
+
终止符使其功能类似于
xargs
。将生成一个shell,并传入所有文件。这也适用于find的所有POSIX版本,不同于
print0
。嗯,我不确定这一点。我刚刚写道,这个开关不相关(正如我在原始问题中提到的),因为手册页对我来说意味着它仅在与生成文件名的开关(例如
-l
)结合使用时才相关。然而,一些初步的测试并不那么清楚。需要更多的调查。对于过早的下推表决表示歉意,我无法撤消。tr解决方案适用于所有没有类似print0选项的命令。使用
-0
-z
开关的关键在于,文件名中可能包含换行符。使用
tr
相当于根本不使用开关。从技术上讲,如果文件名中有换行符,这将失败(无论好坏,这都是合法的)。我从未见过这种情况发生,但这正是人们在解析
ls
-边缘案例时对你(或我)大喊大叫的原因。我不得不使用
--null data
而不是
--null
。我不能100%确定原因,但从
grep--help
中可以看出
--null data
可能会改变grep使用null终止的行为,然而,
--null
将只输出null终止-在处理输入时不考虑它。请提供您的答案的简要说明,以帮助OP和任何未来的访问者理解它的工作原理。我不清楚这是如何解决这个问题的。在我的原始问题中,此样式不会调用
dosomecommand
-print0
选项通常仅用于处理包含换行符而不是其他空格的文件名,因为传统的换行符分隔符(与
-print
一起使用)可以很好地处理这些文件名。
find <somebasedirectory> -print0 | xargs -0 -I % grep something '%'
find <somebasedirectory> -print0 | \
 grep -z stringinfilenamesIwant | \
 grep -zv stringinfilesnamesIdont | \
 xargs -0 dosomecommand