从每一组连续的匹配行中提取第一行



我有一个数据文件,看起来像这样:

a separator
interesting line 1
interesting line 2
a comment
interesting line 3
interesting line 4
interesting line 5
a non interesting line
some other data
interesting line 6
.
.
.

,我想从每个连续的组中提取第一个interesting line,不管组中有多少行,也不管组之间有多少额外的行。

对于上面的测试输入,输出将是:

interesting line 1
interesting line 3
interesting line 6

我可以很容易地在python中做到这一点,通过一个状态变量,当我匹配一行时触发,当我遇到不匹配的行时重置,但是单行shell脚本呢?有什么不太晦涩的方法吗?

您可以将grep与贪婪正则表达式一起使用,然后使用:

打印每个匹配的第一行:
grep -Pzo '([^n]*interesting line[^n](n|$))+' file |
while IFS='' read -d '' -r match
do
head -n1 <<< "$match"
done

grep参数:

  • -P:对于正则表达式中的n使用Perl兼容正则表达式(而不是默认的基本正则表达式)
  • -z:将输入视为一组行,每一行以零字节结束。ASCII NUL字符将分隔每个匹配,允许我们可靠地分隔匹配。
  • 正则表达式([^n]*blablabla[^n]*(n|$))+将匹配包含blablabla的每组连续行。

在while condition命令中,为read清空IFS。否则,使用默认的IFS,每个匹配的最后一个换行字符将被read吃掉(这可能不是问题)。这是一个很好的做法,总是清除IFS在"而读取"使变量中的文本与所读取的完全一致(前导空格也很容易被占用)。

read参数:

  • -d '':使用空字符串作为分隔符(= ASCII NUL字符)。这相当于-d $''(参见https://unix.stackexchange.com/q/61029/283498)。
  • -r:不要解释任何反斜杠(见https://unix.stackexchange.com/q/192786/283498)。
  • match:只是我选择的变量名,用于循环体。

在循环体中:head -n1 <<< "$match"只打印当前匹配的第一行(带有-n 1head命令打印其输入的前1行)。旁注:<<<是一个bashism;该命令相当于echo "$match" | head -n1

最新更新