Linux:如果字符串在列表中的其他位置有子字符串,则从列表中删除这些字符串

Linux:如果字符串在列表中的其他位置有子字符串,则从列表中删除这些字符串,linux,bash,awk,grep,substring,Linux,Bash,Awk,Grep,Substring,我想要一个字符串列表,只保留列表中其他地方没有子字符串的字符串。为了举例说明,我有以下清单: apple applesauce kiwi mango mangoes mangosteen oranges pineapples 我想把它简化为一个字符串列表,列表中其他地方没有任何子字符串。因此,得出的清单将是: apple kiwi mango oranges 请注意,applesauce和pinepples被删除,因为apple在列表中的其他位置,并且是这两个词的子字符串 我发现了一个类似的

我想要一个字符串列表,只保留列表中其他地方没有子字符串的字符串。为了举例说明,我有以下清单:

apple
applesauce
kiwi
mango
mangoes
mangosteen
oranges
pineapples
我想把它简化为一个字符串列表,列表中其他地方没有任何子字符串。因此,得出的清单将是:

apple
kiwi
mango
oranges
请注意,
applesauce
pinepples
被删除,因为
apple
在列表中的其他位置,并且是这两个词的子字符串

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

awk '$1~r && p in k { next } { k[$1]++; print; r= "^" $1; p=$1 }' fruitsorted.txt
即使它像我预期的那样工作,它仍然会错过我列表中的菠萝

请注意,在极端情况下,如果列表包含字母表(或ASCII字符集,我猜)中的所有字母,并且每个字母都位于单独的行上,那么不管列表中还有什么,输出都将是字母表/字符集

此外,我的起始列表未排序。我真的不在乎结果列表是否被排序,尽管这对于
sort
来说显然是微不足道的

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

谢谢

更新

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

apple
applesauce
berryplum
kiwi
mango
mangoes
mangosteen
oranges
pineapples
plum

如果对列表进行排序,它就相当简单

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
性能测试

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

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

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
awk'NR==FNR{f1[NR]=$0;f2[$0]}
结束{
对于(i=0;i=1){
if(长度(j)
如果您觉得有价值,您可以将其全部塞进一行:

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
鉴于:

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

$ 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

我只是尝试了你的建议,但没有效果。尝试如下:
awk'{for(I in a)if(index($0,I))next;a[$0]}1'fruitsorted.txt
,其中
fruitsorted.txt
是我在问题顶部显示的列表。这只是重新打印整个列表,没有删除任何内容。注意,我正在使用Cygwin Bash(minntty 2.7.7).我遗漏了什么吗?谢谢。@SSilk文件是否包含回车符?@123是的,每一行都以回车符和换行符结尾(
CR
LF
,当语法显示在记事本++中打开的所有字符时)@EdMorton对appleplum示例的看法很好。我将更新我的问题,以包含一个类似的示例。请注意,123显示的第二个方法适用于此场景。此方法是否涵盖了下面123显示的第二个示例未涵盖的任何特殊情况?His看起来更紧凑,但可能只是使用了更短的变量名.@SSilk据我所知,它们都涵盖相同的情况。唯一的区别是,每一行都被读入一个数组并读取文件两次以进行更新,而在我的数组中,每一行都被逐行添加到数组中,文件被读取一次。除此之外,它们基本上是相同的。两个答案都将产生相同的结果不管怎样。对,它只是较短的变量名,没有空格。如果你删除我所有的修饰性空格,并将所有变量名更改为单字符,它比123s略短。我知道我的解决方案涵盖了所有可能的情况,idk如果123s遗漏了什么,因为它正在构建我的
结果的等价物数组在飞行中,所以可能有一些情况,它应该检查的东西早在文件中,所以已经跳过了-我真的不知道,仔细考虑,并考虑所有的情况(生命太短,我不能这样做!)。
$ 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