Linux:如果列表

时间:2017-06-23 13:25:26

标签: linux bash awk grep substring

我想获取一个字符串列表,并且只保留列表中其他位置没有子字符串的字符串。为了说明,我有这个清单:

apple
applesauce
kiwi
mango
mangoes
mangosteen
oranges
pineapples

我想将其缩减为列表中没有任何子字符串的字符串列表。因此,结果列表将是:

apple
kiwi
mango
oranges

请注意,applesaucepineapples已被删除,因为apple位于列表中的其他位置,并且是这两个字的子字符串。

我发现了一个类似的问题here,但它似乎专门针对前缀,例如ablaze, able, abler, ablest。基于该方法,我尝试了以下列表的预先排序副本,它只打印了整个列表,甚至没有删除我认为会出现的applesauce

awk '$1~r && p in k { next } { k[$1]++; print; r= "^" $1; p=$1 }' fruitsorted.txt

即使它按预期工作,它仍然会在我的列表中遗漏pineapple

请注意,在一个极端情况下,如果列表包含字母表中的所有字母(或我猜的ASCII字符集),每个字母都在一个单独的行上,那么无论列表中还有什么,输出都只是字母/字符集。

另外,我的开始列表未分类。我真的不在乎结果列表是否已排序,尽管sort显然是微不足道的。

理想情况下,我想要一个有点紧凑的shell命令/序列的东西,比如grep / sort / awk,而不是更长的形式Perl / Python /我已经知道如何实现的任何脚本。

感谢。

更新

正如下面的Ed Morton指出的那样,即使对列表进行排序,也可能会破坏一些基本方法,例如:在下面的示例中,假设排序列表的方法可能无法删除berryplum,因为其子字符串plum位于其后面。 123所示的第二种方法处理了这种情况。

apple
applesauce
berryplum
kiwi
mango
mangoes
mangosteen
oranges
pineapples
plum

4 个答案:

答案 0 :(得分:2)

如果列表已排序,那就非常简单

awk '{for(i in a)if(index($0,i))next;a[$0]}1' file

apple
kiwi
mango
oranges

基本上只是在每个行的数组上循环,并检查行中是否存在元素。如果不是这样,则添加到数组。

对于未排序的列表,这应该有效

awk '{for(i in a){if(index(i,$0)&&$0!=i)delete a[i];if(index($0,i))next}a[$0];next}
     END{for(i in a)print i}' file

Wordlist上测试了性能。

real    0m29.932s
user    0m29.918s
sys     0m0.008s

答案 1 :(得分:1)

$ awk '
   NR==FNR { fruits[$0]; next }
   {
       for (fruit in fruits) {
           if ((fruit != $0) && index($0,fruit)) {
               next
           }
        }
        final[$0]
    }
    END {
        for (fruit in final) {
            print fruit
        }
    }
' file file
mango
apple
oranges
kiwi

如果你发现有价值的话,你可以把它全部塞进一行:

awk 'NR==FNR{fruits[$0];next} {for (fruit in fruits) if ((fruit != $0) && index($0,fruit)) next; final[$0]} END{for (fruit in final) print fruit}' file file

答案 2 :(得分:0)

对于未排序的列表,这可能有所帮助:

awk 'NR==FNR{f1[NR]=$0;f2[$0]}
    END{
    for(i=0;i<=NR;i++){
      for(j in f2){
        if(match(f1[i],j)>=1){
            if(length(j)<length(f1[i])){
            f1[i]="nullfruit"
            }
        }
      }
    }
    for(i=0;i<=NR;i++){
         if(f1[i]!="nullfruit"){
            print f1[i];
            }
    }
    }' filename

apple
kiwi
mango
oranges

注意:非常确定存在更多微妙的解决方案。

答案 3 :(得分:0)

假设:

$ cat f1
apple
applesauce
berryplum
kiwi
mango
mangoes
mangosteen
oranges
pineapples
plum

您可以使用更多循环来避免两次读取文件或关注顺序:

$ awk '{words[$1]}
     END{
        for (e in words)
            for (f in words)
                if (f!=e && index(e,f)) 
                    not[e]   
        for (e in words)
           if (!(e in not))
               print e}' f1
mango
plum
apple
oranges
kiwi