并且,以更通用的方式,是否可以使用程序sed打印匹配PATTERN 1的任何行,但仅当文件中的任何其他行与PATTERN 2匹配时?它可以通过grep命令的组合来完成,但我试图用一个sed命令完成它。
答案 0 :(得分:3)
这不是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
答案 1 :(得分:2)
我相信这是可能的:
: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
根据“bar”的不同,它会打印foo
的所有行,或者根本不打印任何行。
当然,它不会赢得任何选美比赛,但它只是用sed写的。
答案 2 :(得分:1)
这是一个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)匹配的任何行追加到保留空间。遇到bar(pattern2)时,它会使用g
命令获取保留空间的内容(擦除当前模式空间)。它删除了第一个新行(即使保留空间为空,H
命令也会添加一个新行)。如果它包含foo(意味着它不是空的),它会打印出模式空间。然后n
转到下一行。现在我们已匹配pattern2,我们可以通过启动loop2
答案 3 :(得分:1)
这可能适合你(GNU sed):
sed -n ':a;6H;/pattern/{z;H};n;$!ba;x;s/\n//;s///p' file
使用选项-n
关闭图案空间的自动打印。设置一个循环,该循环读取文件的每一行,并在保留空间中附加单行(对于第6行)和/或(不)空行(表示在pattern
上发生匹配)。在文件交换到保留空间的末尾,删除永远存在的第一个换行符(如果已追加行或空行)并删除第二个换行符并在成功时打印结果。
N.B。如果文件中存在pattern
,则保留空间将包含两个换行符,前两个字符或第一个和最后一个字符。
答案 4 :(得分:0)
如果不解析文件两次,一般情况下无法做到这一点。这意味着两次调用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
(退出),以确保文件中稍后的其他触发模式不会搞砸输出。