当字符串出现在多行中时,如何从文件中删除行?

时间:2019-07-07 21:21:07

标签: bash sorting awk sed

我有一个包含2列的文件,如下所示:

apple pear
banana pizza
spoon fork
pizza plate
sausage egg

如果一个单词出现在多行中,我想删除重复出现的单词的所有行,如您所见,“比萨饼”出现了两次,因此应删除2行,以下是必需的输出:

apple pear
spoon fork
sausage egg

我知道要使用:

awk '!seen[$1]++' 

但是,这仅在字符串出现在一列中时才删除行,我需要一条命令来检查两列。 我该如何实现?

5 个答案:

答案 0 :(得分:5)

通过使用grepuniq -d,可以分多个步骤解决问题。

首先,使用grep -Eo '[^ ]+'之类的单词生成所有单词的列表。然后过滤该列表,以便仅保留重复的单词。可以使用… | sort | uniq -d进行过滤。最后,从先前使用grep -Fwvf listFile inputFile生成的列表中打印所有不包含任何单词的行。

bash中,所有这些步骤都可以在一个命令中运行。在这里,我们将使用变量$in使其易于适应。

in="path/to/your/input/file"
grep -Fwvf <(grep -Eo '[^ ]+' "$in" | sort | uniq -d) "$in"

答案 1 :(得分:2)

使用awk,您可以跟踪许多事情。不仅您看到了一个单词,而且看到了单词的哪一行。我们跟踪几个数组。

  • record:跟踪我们解析的每一行
  • seen:跟踪各个单词以及在其上看到的第一个记录编号

这给我们:

awk '{ record[NR]=$0 }
     { for(i=1;i<=NF;++i) {
         if ($i in seen) { delete record[NR]; delete record[seen[$i]] }
         else { seen[$i]=NR }
       }
     }
     END { for(i=1;i<=NR;++i) if (i in record) print record[i] }' file 

这是如何工作的?

  • record[NR]=$0 :将记录$0存储在以记录号record索引的数组NR
  • 对于记录的每个字段/单词,检查该单词之前是否曾出现过。如果已看到,则从数组record中删除原始记录以及当前记录。如果找不到,请将单词和当前记录号存储在数组seen中。
  • 处理完整个文件后,检查我们看到的所有可能的记录号,如果它仍然是数组record的索引,则打印该记录。

答案 2 :(得分:2)

$ awk '
    NR==FNR {
        for (i=1; i<=NF;i++) {
            if ( firstNr[$i] ) {
                multi[NR]
                multi[firstNr[$i]]
            }
            else {
                firstNr[$i] = NR
            }
        }
        next
    }
    !(FNR in multi)
' file file
apple pear
spoon fork
sausage egg

或者,如果您愿意:

$ awk '
    NR==FNR {
        for (i=1; i<=NF;i++) {
            cnt[$i]++
        }
        next
    }
    {
        for (i=1; i<=NF;i++) {
            if ( cnt[$i] > 1 ) {
                next
            }
        }
        print
    }
' file file
apple pear
spoon fork
sausage egg

答案 3 :(得分:0)

这适用于您的示例:

#!/usr/bin/env sh
filename='x.txt'
for dupe in $(xargs -n1 -a "${filename}" | sort | uniq -d); do
  sed -i.bak -e "/\\<${dupe}\\>/d" "${filename}"
done

它会建立一个单词列表,该单词列表在文件中出现多次:

  • xargs -n1 -a "${filename}"输出所有单词的列表
    文件中包含的内容(每行一个字)
  • | sort对列表进行排序
  • | uniq -d仅输出连续出现多次的单词

然后使用sed选择和删除所有包含重复单词的行。

答案 4 :(得分:0)

这可能对您有用(GNU grep,sort,uniq,sed):

///<reference ...

或玩具GNU sed解决方案:

sed 's/ /\n/g' file | sort |uniq -d | grep -vFf - file