我有一个这样的文件(test.txt):
abc
12
34
def
56
abc
ghi
78
def
90
我想搜索被“abc \ nghi”和“def”包围的78。目前,我知道我可以这样做:
cat test.txt | awk '/abc/,/def/' | awk '/ghi/,'/def/'
还有更好的方法吗?
答案 0 :(得分:2)
一种方法是使用标志
$ awk '/ghi/ && p~/abc/{f=1} f; /def/{f=0} {p=$0}' test.txt
ghi
78
def
{p=$0}
这将保存输入行以供将来使用/ghi/ && p~/abc/{f=1}
设置标记,如果当前行包含ghi
且前一行包含abc
f;
打印输入记录/def/{f=0}
,则def
清除该标记
如果你只想要这两个边界之间的界线
$ awk '/ghi/ && p~/abc/{f=1; next} /def/{f=0} f; {p=$0}' ip.txt
78
$ awk '/12/ && p~/abc/{f=1; next} /def/{f=0} f; {p=$0}' ip.txt
34
答案 1 :(得分:0)
这不是很干净,但您可以将记录分隔符重新定义为正则表达式abc\nghi\n|\ndef
。然而,这会创建多个记录,您需要跟踪哪些记录在正确的记录之间。使用awk,您可以使用RT
检查找到哪个RS。
awk 'BEGIN{RS="abc\nghi\n|\ndef"}
(RT~/abc/){s=1}
(s==1)&&(RT~/def/){print $0}
{s=0}' file
这样做:
RS
设置为abc\nghi\n
或\ndef
。RT
包含abc
您找到了第一个记录。RT
包含def
,则打印。答案 2 :(得分:0)
grep
替代
$ grep -Pazo '(?s)(?<=abc\nghi)(.*)(?=def)' file
但我认为awk
会更好
答案 3 :(得分:0)
你可以用sed做到这一点。它并不理想,因为它实际上并不理解记录,但它可能适合你...
// use properties to open the datasource for work
System.out.println("Opening database connection.");
logger.info("Opening database");
String dbDriver = dbProps.get("dbDriver");
String dbURL = dbProps.get("dbURL");
String username = dbProps.get("username");
String password = dbProps.get("password");
Base.open(dbDriver, dbURL, username, password);
logger.info("Database successfully opened.");
这是基本上发生的事情:
sed -Ene 'H;${x;s/.*\nabc\nghi\n([0-9]+)\ndef\n.*/\1/;p;}' input.txt
- 将当前行追加到sed的“保留空间”H
- 指定一旦我们到达文件末尾就会运行的一系列命令的开始${
- 使用模式空间交换保留空间,以便将来的替换可以使用x
H
- 分析模式空间(现在是多行),捕获问题中指定的数据,用括号表达式替换整个模式空间...... s/../../
- 打印结果。这里的一个重要因素是正则表达式是ERE,因此p
选项很重要。如果您的sed版本使用其他选项来启用对ERE的支持,请改用该选项。
另一个考虑因素是上面的正则表达式假设是Unix风格的行结尾。如果您尝试处理在DOS或Windows上生成的文本文件,则正则表达式可能需要稍微不同。
答案 4 :(得分:-1)
awk 解决方案:
awk '/ghi/ && r=="abc"{ f=1; n=NR+1 }f && NR==n{ v=$0 }v && NR==n+1{ print v }{ r=$0 }' file
输出:
78
奖金 GNU awk方法:
awk -v RS= 'match($0,/\nabc\nghi\n(.+)\ndef/,a){ print a[1] }' file