我怎么知道在bash中首先使用awk发生了哪个分隔符?

时间:2018-01-28 13:13:17

标签: bash shell awk sed

如何使用单awk行首先知道哪个分隔符已经发生。

假设我有一个包含内容的文件:

AB BC DE
BC DE AB
DE BC AB

我想知道在每一行中首先发生了三个DEABBC中的哪一个。

我认为我可以使用分隔符BC然后使用第一个字段然后BC,然后取AB的第一个字段。

这可以通过以下方式完成:

$ awk -F'AB' '{print $1}' <file>   \
  | awk -F'BC' '{print $1}' <file> \
  | awk -F'DE' '{print $1}' <file>

但是,有没有其他方法可以动态更改awk行中的分隔符,并且只使用awk一次完成上述操作?

编辑: 纠正了之前的错误。

3 个答案:

答案 0 :(得分:6)

如果这不是您想要的:

awk 'match($0,/AB|BC|DE/){print substr($0,RSTART,RLENGTH)}' file

然后编辑您的问题以阐明您的要求,并提供简明,可测试的样本输入和预期输出。

答案 1 :(得分:4)

首先,如果您的文件仅包含ABBCDEnewline的组合,那么答案很简单:

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