匹配模式后停止grep,而不是整行?长行/单行的文件

时间:2011-05-05 23:19:54

标签: regex grep pattern-matching

我使用grep只返回模式(-o)之间的字符串,在多个文件中,例如

grep -i -r -o 'Rows="[^#][^"]*"' *

我希望它在第一个匹配模式后停止,我尝试了grep -m NUM / --max-count = NUM 但这会在NUM匹配之后停止读取文件,而不是模式,不幸的是,此文件夹中的所有文件都是一条长行。

grep可以在第一个匹配的模式之后停止,或者我应该用其他东西做这个吗?

*奖金问题 - 能够将其输出为“匹配模式”“文件名”,以便我可以对其进行排序吗?

4 个答案:

答案 0 :(得分:0)

据我所知,grep无法做到这一点。实际上,大多数Unix实用程序都是基于行的。例如,我认为没有办法打印sed中只有部分行。即使在awk中,也许有可能将某些东西拼凑在一起,但我的猜测是它会让人不满意。

如果您的系统上有GNU awk,请尝试以下方法:

gawk 'BEGIN {RS="pattern"} {print RT, FILENAME; exit}' filename

RS将记录分隔符(通常是换行符)设置为模式。 RT是由RS匹配的文字。 FILENAME不言自明。 exit停止执行。因此,在第一条记录之后,awk将打印模式文本和文件名,然后退出。这不适用于多个文件,因为此处的退出是无条件的。

如果您需要在目录结构中的所有文件上运行此操作,请使用findxargs,除非您找到了某些内容,否则不要退出:

find . -type f -print0 | xargs -0 gawk 'BEGIN {RS="pattern"} {print RT, FILENAME; if (RT != "") exit}'

这会打印出没有模式的所有内容的文件名(以空格开头),但是当它到达第一个模式时会打印出模式和文件名,然后停止。

当然,您需要对此命令稍加注意:由于记录分隔符可能根本不存在,gawk可能会将文件的全部内容粘贴到其缓冲区中,并且可能会耗尽记忆(当我在我的系统上测试时,我在490 MB时出现故障。)

答案 1 :(得分:0)

想到两个想法;

perl -nle '/(Rows="[^#][^"]*")/ or continue; print $ARGV, ":", $1; exit 0' files ...

然而,这将在处理之前读取整行。另一个想法是在将文件传递给grep之前对文件进行预处理,比如这个hack,也许是:

for file in *; do
    # Replace every R with newline,
    # and every newline with dot.
    # Your tr's syntax for newline may be different
    tr 'R\n' '\n.'  < "$file" |
    sed -n '/^\(ows="[^#][^"]*"\).*/{;s%%'"$file:"'R\1%;p;q;}'
done

你的tr和sed可能与我的不同,所以这可能需要一些调整。

编辑:添加循环,用sed替换grep。

答案 2 :(得分:0)

您可以按以下方式使用BSD grep:

egrep -i -r -o -n 'Rows="[^#][^"]*"' * | egrep '^[^:]+:\d+:'

由于在同一行上输出的其他匹配项没有行号,因此我们仅使用第二个grep过滤掉它们。

不幸的是,GNU grep对此不起作用,因为它输出的每个匹配都带有行号。

ugrep 也很好用(这是我现在最喜欢的,因为它速度快,与GNU / BSD grep兼容,并且具有比GNU / BSD grep更多的功能):

ugrep -i -r -o -n 'Rows="[^#][^"]*"' | ugrep '^[^:]+:\d+:'

顺便说一句:

  1. 对于ugrep,您无需将*与选项-r一起使用,即可将ugrep递归到工作目录中
  2. 要使用第二个grep删除文件名和行号,请​​使用ugrep -P '^[^:]+:\d+:(.*)' --format="%1%~"捕获行号之后的匹配部分,并用%1和换行符%~输出。这需要Perl匹配-P
  

*奖金问题-能够将其输出为“匹配模式”“文件名”,以便我对其进行排序?

像这样:

ugrep -i -r -o -n 'Rows="[^#][^"]*"' | ugrep -P '^([^:]+):\d+:(.*)' --format='"%2" %1%~'

希望这会有所帮助。

答案 3 :(得分:-1)

我没有测试它,但我会尝试:

find -type f -print0 | xargs -0 -r cat | grep -m 1 -i -o 'Rows="[^#][^"]*"'