我有一个这样的清单:
TAGDESCRIPTIONS example
TAGS tmp
TAGS line
TAGDESCRIPTIONS bar
TAGS com
TAGS foo
获取TAGDESCRIPTIONS
的匹配后,awk或grep中的正确命令是什么才能使foo
行与foo
行匹配?因此,在搜索bar
时,会打印{{1}}。
答案 0 :(得分:2)
$ awk '/TAGDESCRIPTIONS/{d=$2} /foo/{print d}' file
bar
答案 1 :(得分:1)
Grep不适用于此,因为它主要用于过滤特定的行,但您询问不同行之间的关系。 Grep可以强制通过(ab)使用-z
标志来执行多行中的某些事物,该标志需要空字节分隔的行,但它通常不漂亮。
Awk 1 允许一个简单的解决方案:
$ awk 'BEGIN{RS="TAGDESCRIPTIONS"}/foo/{print $1}' infile
bar
这会将记录分隔符RS
设置为TAGDESCRIPTIONS
,因此输入被解释为三条记录(\n
代表换行符):
<empty record>
example\nTAGS tmp\nTAGS line\n
bar\nTAGS com\nTAGS foo\n
第一个是空的,因为文件以记录分隔符开头。
对于每条记录,我们在第一个换行符之前的内容是标记描述。我们用
说什么/foo/{print $1}
是这样的:如果记录与foo
匹配,则打印记录的第一个字段(描述)。
这根本不是防弹的。如果描述由多个单词组成,则仅打印第一个单词。如果描述而不是标记匹配,那就是误报。如果记录包含foobar
但不包含bar
,则该记录仍会匹配。
这个输入示例将抛弃简单的解决方案:
TAGDESCRIPTIONS foo
TAGS blah
TAGDESCRIPTIONS example
TAGS tmp
TAGS line
TAGS foobar
TAGS barfoo
TAGDESCRIPTIONS bar and more words
TAGS com
TAGS foo
标记说明包含foo
,标记包含 foo
,标记说明包含多个字词。
我们可以通过在新行分割记录,然后将除描述之外的每个元素与搜索字符串进行比较来解决所有问题:
awk '
BEGIN { RS = "TAGDESCRIPTIONS *" }
{
# Split record at newlines, store in arr
split($0, arr, "\n")
# Skip first element (description), compare to 'foo'
for (i = 2; i <= length(arr); ++i) {
if (arr[i] ~ " +foo$") {
# Matches - print description
print arr[1]
# No need to look at the rest of the record
break
}
}
}' infile
导致
bar and more words
1 GNU awk,确切地说,由于多字符记录分隔符和length
函数。
答案 2 :(得分:0)
我会试一试 我不知道grep或awk,但下面只是一个原始正则表达式 使用PCRE样式前瞻和内联修改器组。
(?ms)^TAGDESCRIPTIONS\s+(\w*)\s+(?:(?!^TAGDESCRIPTIONS).)+^TAGS\s+foo
扩展
(?ms)
^ TAGDESCRIPTIONS \s+
( \w* ) # (1)
\s+
(?:
(?! ^ TAGDESCRIPTIONS )
.
)+
^ TAGS \s+ foo
bar
字在捕获组1中。根据需要充实正则表达式。
输出
** Grp 0 - ( pos 68 , len 83 )
TAGDESCRIPTIONS bar
TAGS com
TAGS foo
** Grp 1 - ( pos 84 , len 3 )
bar