早上好,这和问题非常相似Grep 从最后一次出现的模式到另一个模式(几个月前),同时添加更多细节。
我正在尝试为具有多个重复模式的文件编写 UNIX 脚本,后跟我要查找的模式。但是,我没有“tac”或“tail -r”(使用 UNIX 模拟器 MKS Toolkit),并且希望返回 Pattern2 之前最后一次出现的 Pattern1,然后是 Pattern1 和 Pattern2 之间的数据,然后是 Pattern2还。本例中的模式为“条件 1”和“条件 2”:
输出:
...
Condition 1: A
data1
Condition 1: B
data2
Condition 2: C
data3
Condition 1: D
data4
Condition 1: E
data5
Condition 2: F
...
我想编写一个 awk (或 sed,但认为 awk 将是正确的工具)脚本来返回:
Condition 1: B
data2
Condition 2: C
Condition 1: E
data5
Condition 2: F
我认为这是下面一行的某种形式,但我无法正确理解语法:
awk '/Condition 1/ {acc = $0;} /,/Condition 2/ {print ?}' output.out
使用“/,/”似乎是我遇到困难的地方。想知道是否有人有任何建议,将不胜感激。非常感谢与此问题相关的任何帮助和时间。
答案1
尝试:
$ awk 'f{a=a"\n"$0} /Condition 1/{a=$0; f=1} f && /Condition 2/{print a; f=0}' output.out
Condition 1: B
data2
Condition 2: C
Condition 1: E
data5
Condition 2: F
怎么运行的
f{a=a"\n"$0}
如果变量
f
为真(非零),则将当前行附加到变量的末尾a
。/Condition 1/{a=$0; f=1}
如果当前行包含
Condition 1
,则设置s
为当前行并将变量设置f
为 1。f && /Condition 2/{print a; f=0}
如果
f
为 true 并且当前行包含Condition 2
,则打印变量a
并设置f
回零。
答案2
当您希望在文本处理中进行反向寻址时,请使用ex
它是POSIX 指定vi
,它是(以及vi
它的直接前身)的可编写脚本的形式——非常灵活。
printf '%s\n' 'g/Condition 2/?Condition 1?,.p' | ex output.out
这意味着:
对于与模式“条件 2”匹配的每一行(g
全局),向后搜索“条件 1”的前一个实例,并p
打印从该行到当前行 ( .
) 的所有行(即带有“条件 2”的行)它)。
提供的输入的输出与您所描述的完全相同。
答案3
sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x' infile
尽管这假设任何匹配的行PATTERN_2
前面至少有一个匹配的行PATTERN_1
。对于更一般的情况,添加另一个条件来PATTERN_1
在打印之前测试模式空间中是否存在:
sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x;/PATTERN_1/!d' infile
答案4
这是 Perl 的一个邪恶之处:
perl -0777 -ne '
my $c1 = qr/Condition 1/;
my $c2 = qr/Condition 2/;
print for map {s/$c2.*?\n\K.*//s; $_}
grep {/$c2/}
split /(?=$c1)/ms;
' output.out
它:
- 读取整个文件(使用
-0777
和-n
选项), - 在出现条件 1 的位置将其拆分 (
split
), - 过滤掉条件 2 未出现的段落 (
grep
), - 然后从每个感兴趣的段落中删除条件 2 行 (
map
) 之后的所有行。