我经常想写这样的命令(在zsh
中,如果它是相关的):
find <somebasedirectory> | \
grep stringinfilenamesIwant | \
grep -v stringinfilesnamesIdont | \
xargs dosomecommand
(或更复杂的greps组合)
近年来,find
添加了-print0
开关,xargs添加了-0
,它允许通过空终止文件名以优雅的方式处理名称中包含空格的文件相反,允许这样:
find <somebasedirectory> -print0 | xargs -0 dosomecommand
然而,grep
(至少我有的版本,Ubuntu上的GNU grep 2.10),似乎没有等效消耗和生成以null结尾的行;它有--null
,但这似乎与使用-l
直接用grep搜索文件时输出名称有关。
我可以使用grep的等效选项或选项组合吗?或者,是否有一种简单而优雅的方式来表达我的命令管道,只需使用find -regex
,或者Perl?
答案 0 :(得分:41)
--null
标志根据GNU Grep documentation,您可以使用输出行前缀控制来处理ASCII NUL字符,方法与 find 和 xargs 相同。
-Z
--null
输出零字节(ASCII NUL字符),而不是通常在文件名后面的字符。例如,'grep -lZ'在每个文件名后输出一个零字节,而不是通常的换行符。即使存在包含不常用字符(如换行符)的文件名,此选项也会使输出明确无误。此选项可与“find -print0”,“perl -0”,“sort -z”和“xargs -0”等命令一起使用,以处理任意文件名,甚至是包含换行符的文件名。
tr
正如OP正确指出的那样,在输入或输出上处理文件名时,此标志最有用。为了实际转换grep输出以使用NUL字符作为行结尾,您需要使用 sed 或 tr 之类的工具来转换每行输出。例如:
find /etc/passwd -print0 |
xargs -0 egrep -Z 'root|www' |
tr "\n" "\0" |
xargs -0 -n1
此管道将使用NUL将文件名与 find 分开,然后将换行符转换为 egrep 返回的字符串中的NUL。这会将NUL终止的字符串传递给管道中的下一个命令,在这种情况下只是 xargs 将输出转换回普通字符串,但它可能是你想要的任何东西。
答案 1 :(得分:5)
由于您已经在使用GNU find
,因此您可以使用其内部正则表达式模式匹配功能而不是这些grep
,例如:
find <somebasedirectory> -regex ".*stringinfilenamesIwant.*" ! -regex ".*stringinfilesnamesIdont.*" -exec dosomecommand {} +
答案 2 :(得分:3)
最新版本的GNU grep源现在可以使用-z
/ --null
将输出与空字符分开,而以前只能与-l
一起使用:
http://git.savannah.gnu.org/cgit/grep.git/commit/?id=cce2fd5520bba35cf9b264de2f1b6131304f19d2
这意味着您在使用最新版本时会自动解决您的问题。
答案 3 :(得分:2)
您可以将查找-exec
与+
终结符一起使用,而不是使用管道。要将多个命令链接在一起,可以在-exec
中生成一个shell。
find ./ -type f -exec bash -c 'grep "$@" | grep -v something | xargs dosomething' -- {} +
答案 4 :(得分:2)
使用
find <somebasedirectory> -print0 | \
grep -z stringinfilenamesIwant | \
grep -zv stringinfilesnamesIdont | \
xargs -0 dosomecommand
但是,该模式可能不包含换行符,请参阅bug report。
答案 5 :(得分:-3)
find <somebasedirectory> -print0 | xargs -0 -I % grep something '%'