我想以相反的顺序获取与模式匹配的行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
,它也可以工作,但是由于g
lobal 命令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