如何使用grep将输出拆分为两个文件?

yuk*_*say 15 grep io-redirection

我有一个mycommand.sh不能运行两次的脚本。我想将输出拆分为两个不同的文件,一个文件包含与正则表达式匹配的行,另一个文件包含与正则表达式不匹配的行。我希望拥有的基本上是这样的:

./mycommand.sh | grep -E 'some|very*|cool[regex].here;)' --match file1.txt --not-match file2.txt
Run Code Online (Sandbox Code Playgroud)

我知道我可以将输出重定向到一个文件,然后使用和不使用 -v 选项重定向到两个不同的 grep 并将它们的输出重定向到两个不同的文件。但我只是想知道是否可以用一个 grep 来做到这一点。

那么,是否有可能在一行中实现我想要的?

Joh*_*024 22

有很多方法可以实现这一点。

使用 awk

以下发送coolregex与 file1匹配的任何行。所有其他行转到文件 2:

./mycommand.sh | awk '/[coolregex]/{print>"file1";next} 1' >file2
Run Code Online (Sandbox Code Playgroud)

这个怎么运作:

  1. /[coolregex]/{print>"file1";next}

    任何与正则表达式匹配的行都会coolregex打印到file1. 然后,我们跳过所有剩余的命令并跳转到重新开始就next行了。

  2. 1

    所有其他行都发送到标准输出。 1是 awk 的 print-the-line 的神秘简写。

也可以拆分为多个流:

./mycommand.sh | awk '/regex1/{print>"file1"} /regex2/{print>"file2"} /regex3/{print>"file3"}'
Run Code Online (Sandbox Code Playgroud)

使用进程替换

这不像 awk 解决方案那么优雅,但为了完整起见,我们还可以使用多个 grep 结合进程替换:

./mycommand.sh | tee >(grep 'coolregex' >File1) | grep -v 'coolregex' >File2
Run Code Online (Sandbox Code Playgroud)

我们也可以分成多个流:

./mycommand.sh | tee >(grep 'coolregex' >File1) >(grep 'otherregex' >File3) >(grep 'anotherregex' >File4) | grep -v 'coolregex' >File2
Run Code Online (Sandbox Code Playgroud)


Min*_*Max 8

sed -n -e '/pattern_1/w file_1' -e '/pattern_2/w file_2' input.txt
Run Code Online (Sandbox Code Playgroud)

w filename - 将当前模式空间写入文件名。

如果您希望所有匹配的行都转到file_1并且所有不匹配的行转到file_2,您可以执行以下操作:

sed -n -e '/pattern/w file_1' -e '/pattern/!w file_2' input.txt
Run Code Online (Sandbox Code Playgroud)

或者

sed -n '/pattern/!{p;d}; w file_1' input.txt > file_2
Run Code Online (Sandbox Code Playgroud)

解释

  1. /pattern/!{p;d};
    • /pattern/!- 否定 - 如果一行不包含pattern.
    • p - 打印当前模式空间。
    • d- 删除模式空间。开始下一个循环。
    • 因此,如果一行不包含模式,它会将这一行打印到标准输出并选择下一行。file_2在我们的例子中,标准输出被重定向到。当该行与模式不匹配时,不会到达sed脚本的下一部分( w file_1)。
  2. w file_1- 如果一行包含模式,/pattern/!{p;d};则跳过该部分(因为它仅在模式不匹配时执行),因此,该行转到file_1.