文本处理 - 如何获取模式 A 匹配行,直到第一次出现模式 B 匹配行?

文本处理 - 如何获取模式 A 匹配行,直到第一次出现模式 B 匹配行?

我想以相反的顺序获取与模式匹配的行A与第一次出现的模式匹配的行匹配线及其经过的线。

更新:example_file.txt

ISA*00*          *00*          *ZZ*SIX-SIX6      *12*666666666666     *66666666*6666*U*666666666*6666666666*0*P*\
GS*FA*SIX-SIX-SIX*666666666*6666666*6666*6666*X*66666
ST*666*666
AK1*SX*666
AK2*777*6666666
AK5*A
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5
AK2*777*6666666
AK5*A
AK2*777*69696969
AK3*J7*5**3
AK4*3*6969*4
AK5*R*5
AK9*P*20*20*19
SE*69*6969
GE*1*6767
IEA*1*0000000000

我想要的是从下到上获得其后的所有AK5模式,如下所示:R

图案A:AK5*R

并让所有行向上直到模式第一次出现已匹配。例如:

图案:AK2

所需输出:

第一种模式A匹配的将被调用E1

AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5

更新:第二种模式A匹配的将被调用E2

AK2*777*69696969
AK3*J7*5**3
AK4*3*6969*4
AK5*R*5

如果有超过 1 个模式,依此类推A匹配。

编辑:我知道sed可以做到这一点,但我仍然没有运气从每个模式 A 中获取与其第一次出现的模式 B 匹配的行,并将它们存储在临时文本文件中以供进一步处理。

这是我的示例sed命令,它获取所有可用的模式在里面example_file.txt

sed -ne '/AK2\*/,/\AK5\*R/p' example_file.txt

命令逻辑场景示例:

A="AK5\*R"
B="AK2"

find the first $A < example_file.txt; # AK5\*R
move to previous line until first occurrence of $B line; # AK2*any_number*any_number
get all lines from first $A to its first occurrence of $B and store in a text file; # result > e1.txt
# The same way goes to the second occurrence of pattern A.

(注意: $B 的第一次出现意味着,从每个 $A 行开始获取 $A 行和前面的行,直到它遇到的第一个 $B 匹配行。例如,如果第一个 $A 行从 a 的中间行开始文件如第 50 行,如果文件总共有 100 行,则从那里移动到上一行,直到命令遇到它看到的第一个 $B 行。)请参阅下面的示例。

示例_文件2.txt

ISA*00*          *00*          *ZZ*SIX-SIX6      *12*666666666666     *66666666*6666*U*666666666*6666666666*0*P*\
GS*FA*SIX-SIX-SIX*666666666*6666666*6666*6666*X*66666
ST*666*666
AK1*SX*666
AK2*777*6666666
AK5*A
AK2*777*7777777
AK5*A
AK2*777*888888
AK5*A
AK2*777*7777777
AK5*A
AK2*777*5555555
AK5*A
AK2*777*7777777
AK5*A
AK2*777*4545435
AK5*A
AK2*777*7777777
AK5*A
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*A
AK2*777*0987654
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*A
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*A

输出:

AK2*777*0987654
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5

答案1

再次阅读您的描述,我明白您希望从下到上模式 B 的第一个匹配,直到(向上)模式 A 的第一个匹配。但是生成的部分应该按照文件的顺序排列。

这需要很多逻辑。下列脚本完成了这一切。将结果以正确的内部顺序放置在文件E和一些数字中,第一个文件 ( E1) 将具有从顶部开始的第一个匹配项,最后一个文件将具有最后一个匹配部分。

#!/bin/bash

rm -rf resE* E*

tac ../example_file.txt |
    awk 'BEGIN{i=1}
         /^AK5\*R.*/{p=1}
         {if(p==1){f="resE" i;print($0)>>f;close(f)}}
         /^AK2.*/{if(p==1){i++};p=0}
        '
set -- resE* 
c=$#
for (( i=1;i<=$c;i++)); do
    pos=$(($c-$i+1))
    [ -f "$1" ] && tac "$1" > "E$pos"
    shift
done

结果范围将是:

$ cat E1
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5

$ cat E2
AK2*777*7777777
AK3*J7*5**3
AK4*3*6969*4
AK5*R*5

答案2

POSIXex再次来救援!

ex是 POSIX 指定的可编写脚本的文件编辑器。对于任何涉及向后寻址的问题,它通常是比 Awk 或 Sed 更好的解决方案。

下面的一句话非常适合您example_file2.txt

printf '%s\n' 'g/AK5[*]R/?AK2?,.p' | ex example_file.txt

在您的 上example_file.txt,它也可以工作,但是由于global 命令ex无法针对每个作用范围写入单独的目标,因此所需的两个输出文件将像这样合并:

AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5
AK2*777*69696969
AK3*J7*5**3
AK4*3*6969*4
AK5*R*5

然而,这很容易处理——使用另一个 POSIX 工具,csplit它旨在根据“上下文”分割文件。

便携式 POSIX 解决方案:

patA='AK5[*]R'
patB='AK2'

printf '%s\n' "g/$patA/?$patB?,.p" |
  ex example_file.txt |
  csplit -f my_unique_prefix_ -n 1 -s -k - "/$patB/" '{999}'

for f in my_unique_prefix_*; do
  mv "$f" "e${f##my_unique_prefix_}.txt";
done

rm e0.txt

要使其成为完美的解决方案,还有最后一个要素,即以相反的顺序对文件重新编号。这部分我还没做。


如果您不关心文件编号与文件的顺序相同,并且不介意是否.txt省略扩展名,并且不介意文件的编号是 frome01而不是 from e1,并且如果您不介意打印有关每个文件中放入了多少行的诊断消息,那么我们可以简化:

patA='AK5[*]R'
patB='AK2'

printf '%s\n' "g/$patA/?$patB?,.p" |
  ex example_file.txt |
  csplit -f e -k - "/$patB/" '{999}'

rm e00

相关内容