如何使用单awk
行首先知道哪个分隔符已经发生。
假设我有一个包含内容的文件:
AB BC DE
BC DE AB
DE BC AB
我想知道在每一行中首先发生了三个DE
,AB
,BC
中的哪一个。
我认为我可以使用分隔符BC
然后使用第一个字段然后BC
,然后取AB
的第一个字段。
这可以通过以下方式完成:
$ awk -F'AB' '{print $1}' <file> \
| awk -F'BC' '{print $1}' <file> \
| awk -F'DE' '{print $1}' <file>
但是,有没有其他方法可以动态更改awk行中的分隔符,并且只使用awk一次完成上述操作?
编辑: 纠正了之前的错误。
答案 0 :(得分:6)
如果这不是您想要的:
awk 'match($0,/AB|BC|DE/){print substr($0,RSTART,RLENGTH)}' file
然后编辑您的问题以阐明您的要求,并提供简明,可测试的样本输入和预期输出。
答案 1 :(得分:4)
首先,如果您的文件仅包含AB
,BC
或DE
与newline
的组合,那么答案很简单:
awk '{print $1}' file
这符合你的榜样。尽管如此,我不相信这种情况。 按理说,Ed Morton的解决方案显然是前进的方式!它干净,简单,最重要的是单线。
然而,从纯粹的教育角度来看,这里提出了一种不同的awk
方法。
如果要在一行中找到“第一个”分隔符,可以从另一个角度解决问题。您可以将其理解为一组记录,而不是将该行解释为一组列。这带来的问题是“首先找到了哪个记录分隔符:
RT
(gawk extention) 与RS
表示的文本匹配的输入文本,记录 分隔器。每次读取记录时都会设置它。
对于单行字符,您可以执行以下操作:
$ echo "AB BC DE BC DE AB DE BC AB" \
| awk 'BEGIN{RS="DE|AB|BC"}{print RT;exit }'
AB
现在可以更多地使用这个想法了。不断在换行符和请求的集之间切换RS
。这只是为了表明awk
的灵活性。
$ awk 'BEGIN{RSSET="DE|AB|BC";RS=RSSET}
(RS=="\n"){RS=RSSET;next}
{print RT; RS="\n"; next}' file
如果文件是
AB BC DE BC DE AB DE BC AB
BC DE AB DE BC AB
DE AB DE BC AB
输出
AB
BC
DE
答案 2 :(得分:1)
标记为sed
的解决方案。 sed
的贪婪本性让这更令人困惑,但我认为以下是有效的。
#!/usr/bin/sed -rnf
# This presumes you only want to print matching rows.
/(AB|CD|EF)/ {
# add a line number
=;
# find first match, then remove rest of line
s/(AB|CD|EF).*$/\1/;
# this only leaves one possible match, so the greedy match all
# at the start doesnt match what we want.
s/^.*(AB|CD|EF)/\1/;
# so print.
p
}
举个例子,我已经更改了'代码'来检查它是第一个匹配的代码:
~$> printf "%b\n" "$letters"
ABa BBa ABb BBb ABc BBc
BBc ABc BBb ABb BBa ABa
ABb ABc BBa BBc
not right
~$> echo "$letters" | sed -rn '/(AB.|BB.)/ {=; s/(AB.|BB.).*$/\1/; s/^.*(AB.|BB.)/ \1/; p }'
1
ABa
2
BBc
3
ABb