并且,以一种更通用的方式,是否可以使用sed程序打印任何与模式1匹配的行,但前提是文件中的任何其他行与模式2匹配?它可以用grep命令的组合来完成,但我正试图用一个sed命令来完成。
这不是sed的作业:
awk 'NR==FNR{if (/PATTERN2/) f=1; next} f && (FNR==6)' file file
awk 'NR==FNR{if (/PATTERN2/) f=1; next} f && /PATTERN1/' file file
或者如果您不想指定两次文件名:
awk 'BEGIN{ARGV[ARGC]=ARGV[ARGC-1]; ARGC++} NR==FNR{if (/PATTERN2/) f=1; next} f && /PATTERN1/' file
我相信这是可能的:
:l1 {
/foo/ { H }
/bar/ { x ; s/^n//; p ; s/.*//; h ; b l2}
n
b l1
}
:l2 {
/foo/ { p }
n
b l2
}
快速概览:
l1是我们的初始循环。它将检查/foo/
(为模式1(。如果它是在一条线上找到的,那么这条线就会被吸引到容纳空间。下一行将检查/bar/
,当找到时,它将交换保持空间和模式空间(x
(,从数据中删除一个初始换行符(这是因为我们在第一行中使用H
,我们p
打印数据,我们清空此数据并将其存储回保持模式中(因此它将为空(。然后,我们b
分支到l2
,实际上,离开了循环l2
。
如果该行与模式1 foo
或模式2 bar
不匹配,它将转到下一行,并再次跳回到起始l1
。
一旦我们进入l2
,我们就检查模式1 /foo/
。既然我们知道我们早些时候发现了模式2(否则我们就不会在这里了(,我们就可以安全地打印这些数据。如果不是foo,我们就跳过这一行,循环回到l2
的开头。
用以下数据进行了大量测试:
a
b
c foo
d
e foo
f bar
g foo
h
i foo
j
k
根据存在的"条",它要么用foo
打印所有行,要么什么都不打印。
诚然,它不会赢得任何选美比赛,但它只是用sed写的。
这里有一个sed脚本,它打印匹配pattern1的行,如果存在匹配pattern2的行,则不管pattern1、pattern2:的顺序如何
#n
:loop
/foo/H
/bar/{
g
s/n//
/foo/p
:loop2
n
/foo/p
b loop2
}
n
b loop
如果你把它保存到像s.sed这样的文件中,你就可以进行
sed -f s.sed file
#n
的工作方式与-n相同,表示抑制标准输出。loop
将匹配foo(pattern1(的任何行附加到保持空间。当它遇到条(pattern2(时,它会用g
命令获取保持空间的内容(擦除当前的模式空间(。它删除第一个新行(因为即使保持空间为空,H
命令也会添加新行(。如果它包含foo(意味着它不是空的(,它就会打印出模式空间。然后n
转到下一行。现在我们已经匹配了pattern2,我们可以通过启动loop2
这可能对你有用(GNU sed(:
sed -n ':a;6H;/pattern/{z;H};n;$!ba;x;s/n//;s///p' file
使用选项-n
关闭图案空间的自动打印。设置一个循环,读取文件的每一行,并在保持空间中附加一行(针对第6行(和/或空行(表示已在pattern
上发生匹配(。在文件交换到保留空间结束时,删除一直存在的第一个换行符(如果附加了一行或空行(,并删除第二个换行符,如果成功,则打印结果。
N。B.如果文件中存在pattern
,则保留空间将包含两个换行符——前两个字符或第一个和最后一个字符。
在一般情况下,如果不解析两次文件,就无法做到这一点。这意味着调用sed
两次。
如果匹配"触发模式"的行总是在匹配"匹配模式"的所有行出现之后出现,那么这可能会为您做到:
$ cat testdata
1 aaa
2 match
3 match
4 ddd
5 trigger (only print line 2 and 3 if this line is present)
$ sed -n -e '/match/H' -e '/trigger/{x;^Mp;^M;q^M}' testdata
2 match
3 match
(^M
中有逐字换行(
我不知道如何删除输出中最初的空行。欢迎对此提出意见。
更新:我在"触发器模式"的命令序列的末尾放了一个最终的q
(退出(,只是为了确保文件后面的其他触发器模式不会破坏输出。