提取具有非连续字符串的两个连续行

Extract two consecutive lines that have non-consecutive strings

我有一个非常大的文本文件,有 2 列和超过 10 mio 行。 大多数行在第 2 列中都有一个数字,该数字是上一行的第 2 列的数字 +1。但是,几千行的行为有所不同(请参见下面的示例)。

输入文件:

A  1
A  2
A  3
A  10
A  11
A  12
A  40
A  41

我想提取第 2 列中不符合 +1 增量的两行。

所需的输出文件:

A  3
A  10
A  12
A  40

是否有(优先)允许这样做的 awk 命令? 我尝试了几个代码来比较连续两行的第 2 列,但不幸的是我直到现在都失败了(见下面的代码)。

awk 'FNR==1 {print; next} ==p2+1 {print p [=12=]; p=""; next} {p=[=12=] ORS; p2=}' input.txt > output.txt

感谢您的帮助。最好的,

假设:

  • 列是 tab-delimited
  • 第 1 列可能包含白色 space(这在 OP 提供的样本中没有显示,但也没有排除)
  • 感兴趣的行必须在第 1 列中具有相同的值(即,如果第 1 列中的值不同,那么我们不会费心比较第 2 列中的值,而是继续下一个输入行)
  • 如果连续3行符合条件,则第2/中间行只打印一次

设置:

$ cat input.txt
A       1
A       2
A       3           # match
A       10          # match
A       11
A       12          # match
A       23          # match
A       40          # match
A       41
X to Z  101
X to Z  102         # match
X to Z  104         # match
X to Z  105

注意: 注释仅在此处添加以突出显示符合搜索条件的行

一个awk想法:

awk -F'\t' '
FNR==1 { prevline=[=11=] }
FNR>1  { if ( == prev1 && +0 != prev2+1) {
            if (prevline) print prevline
            print
            prevline=""                          # make sure this line is not printed again if next line also meets criteria
         }
         else 
            prevline=[=11=]
       }
       { prev1=; prev2= }
' input.txt

这会生成:

A       3
A       10
A       12
A       23
A       40
X to Z  102
X to Z  104

我喜欢 perl 用于需要算术的文本处理。

$ perl -ane 'print and next if $.<3; print $p and print if $F[3]!=$fp+1; $fp=$F[3]; $p=$_' input.txt
| COLUMN 1 | COLUMN 2 |
| -------- | -------- |
| A | 3 |
| A | 10 |
| A | 12 |
| A | 40 |
  • 这是使用 -a 自动拆分为 @F
  • 打印前两行:print and next if $.<3
  • 在后续行中,如果第 4 个字段不正好比前面的第 4 个字段多一个,则打印前一行和当前行:print $p and print if $F[3]!=$fp+1
  • 将第 4 个字段保存为 $fp,将整行保存为 $p: $fp=$F[3]; $p=$_

请您尝试以下操作:

awk 'NR>1 {if (!=p2+1) print p ORS [=10=]} {p=[=10=]; p2=}' input.txt > output.txt

输出:

A  3
A  10
A  12
A  40
  • 变量名称与您的相似:p 保留上一行和 p2 保存上一行的第二列。
  • 条件NR>1禁止在第一行打印。
  • if (!=p2+1) print p ORS [=15=] 打印成对的两行 满足条件
  • {p=[=16=]; p2=}为下一次迭代保留当前行的值。

这可能适合您 (GNU sed):

sed -nE 'N;h
         s/.*\s+(.*)\n.*(\s.*)/echo "$((+1))"/e;/^(.*)\s$/!{x;p;x};x;D' file 

在整个文件中打开两行 window。

复制 window 并将第一行的第二列增加一。如果此修改后的值等于第二行的第二列,则打印这两行。

删除第一行并重复。

N.B。如果下一行满足相同的条件,这可能会将这些行中的第二行打印两次。