如果$ previous_line与$ current_line相匹配,则不打印。*

时间:2018-08-13 09:28:06

标签: regex bash awk

我希望能够使用awk代替while循环,以从输入字符串中删除子域(如果它也包含主域)。

源文件:

1234.f.dsfsd.test.com
abc.test.com
ad.sdk.kaffnet.com
amazon.co.uk
analytics.test.dailymail.co.uk
bbc.co.uk
bbc.test.com
dailymail.co.uk
kaffnet.com
sdk.kaffnet.com
sub.test.bbc.co.uk
t.dailymail.co.uk
test.amazon.co.uk
test.bbc.co.uk
test.com
test.dailymail.co.uk

所需的输出:

amazon.co.uk
bbc.co.uk
dailymail.co.uk
kaffnet.com
test.com

解决方案:@EdMorton

4 个答案:

答案 0 :(得分:4)

检查域的最后一部分,看看其中哪一个是最短的字符串:

BEGIN{FS="."}
{
    ind=$(NF-1) FS $NF;
    if (!(ind in size)  || (size[ind] > length)) {
       size[ind]=length  # check the minimum size for this domain
       domain[ind]=$0    # store the string with the minimum size on this domain
    }
}

END {for (ind in domain) print domain[ind]}

单线:

$ awk 'BEGIN{FS="."} {ind=$(NF-1) FS $NF; if (!(ind in size)  || (size[ind] > length)) { size[ind]=length; domain[ind]=$0}} END {for (ind in domain) print domain[ind]}' file
test.com
bbc.co.uk

以前的方法适用于顶级域:

只需使用字段分隔符并将其设置为点即可。这样,只需将倒数第二个和倒数第二个存储为字符串,然后检查您发现多少个不同的问题即可。

$ awk -F. '{a[$(NF-1) FS $NF]} END{for (i in a) print i}' file
test.com

这是如何工作的? a[]是一个数组,我们一直在其中添加索引。索引是用倒数第二个字段,一个点和最后一个字段定义的。这样,任何新的bla.test.com仍将具有相同的索引,并且不会在数组中添加额外的信息。

使用其他输入:

$ cat file
1234.f.dsfsd.test.com
abc.test.com
bbc.test.com
test.com
bla.com
another.bla.com
$ awk -F. '{a[$(NF-1) FS $NF]} END{for (i in a) print i}' file
test.com
bla.com

答案 1 :(得分:2)

基于新要求和新示例输入文件的新答案:

$ cat tst.awk
{ doms[$0] }
END {
    for (domA in doms) {
        hasSubDom = 0
        for (domB in doms) {
            if ( index(domA,domB ".") == 1 ) {
                hasSubDom = 1
            }
        }
        if ( !hasSubDom ) {
            print domA
        }
    }
}

$ rev file | awk -f tst.awk | rev
bbc.co.uk
dailymail.co.uk
amazon.co.uk
kaffnet.com
test.com

$ rev file | sort |
  awk -F'.' 'index($0,prev FS)!=1{ print; prev=$1 FS $2 }' |
  rev
bbc.co.uk
test.com

以上只是实现您在问题中描述的算法。它反转每一行的字符,然后像您已经在做的那样对结果进行排序,然后如果前一行是foo.bar.stuff,则prevfoo.bar,因此如果当前行是{ {1}},然后调用索引将发现foo.bar.otherstuff(注意最后的foo.bar.-将最后的.添加到比较中很重要,这样.不会不会错误地匹配foo.bar)确实发生在当前行的开头(索引位置1),因此我们不会打印该行,而foo.barristers.wig将保持原样。另一方面,如果当前行是prev,则在该行的开头不会出现my.sharona.songprev),因此该行将被打印并且foo.bar设置为prev。最后,它只是将每条输出线上的字符恢复为原始顺序。

答案 2 :(得分:1)

如果使用<div class="page"> <div class="oe_structure"/> <div class="col-xs-6 pull-left"> <h2 style="color:red"> <span>Plan Order : <span style="color:Red" t-field='doc.name'/> </span> </h2> </div> <div colspan="4" class="col-xs-6 text-right"> <span> <img t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' % ('Code128', doc.name, 500, 50)" style="width:100%;height:50px"/> </span> </div> 运算符构建变量,则可以在awk中测试动态正则表达式

~

Example(使用tac和rev来促进还原)

您的方法的问题在于,由于仅显示前一行,因此您至少需要2行用于该域,但是如果您没有前一行?如果您的域总是至少包含2行,那么对您来说这可能不是问题。

答案 3 :(得分:1)

对于它的价值而言,这是一个不需要重新输入和排序就可以工作的版本。

awk -F. 'BEGIN {
    SLDs = "co.uk,gov.uk,add.others" # general-use second-level domains we recognize
    split(SLDs, slds, /,/);
    for (i in slds) slds[slds[i]] = 1
}
/./ {
    tld = $(NF-1) "." $(NF)
    if (NF > 2 && tld in slds) tld = $(NF-2) "." tld
    lines[NR] = $0
    tlds[NR] = tld
    if (tld == $0) existing_tlds[tld] = 1
}
END {
    for (i = 1; i <= length(lines); i++) {
        line = lines[i]; tld = tlds[i]
        if (!(tld in existing_tlds) || tld == line) print(line)
    }
}' input_file

这将遍历文件并构建一个现有TLD阵列。在END块中,仅当它是TLD本身 或该数组中不存在其TLD时,才打印一行。

input_file

1234.f.dsfsd.test.com
abc.test.com
amazon.co.uk
bbc.co.uk
bbc.test.com
sub.test.bbc.co.uk
test.amazon.co.uk
test.bbc.co.uk
test.com

它打印

amazon.co.uk
bbc.co.uk
test.com