![](/img/trans.png)
[英]How can i remove multiple lines from a file based on a pattern that spans multiple lines?
[英]How can i remove lines from a file when a string appears on multiple lines?
我有一个具有2列的文件,如下所示:
apple pear
banana pizza
spoon fork
pizza plate
sausage egg
如果一个单词出现在多行中,我想删除重复出现的单词的所有行,如您所见,“比萨饼”出现了两次,因此应删除2行,以下是必需的输出:
apple pear
spoon fork
sausage egg
我知道使用:
awk '!seen[$1]++'
但是,这仅在字符串出现在一列中时才删除行,我需要一条将检查两列的命令。 我怎样才能做到这一点?
您可以使用grep
和uniq -d
多个步骤解决问题。
首先,使用grep -Eo '[^ ]+'
类的东西生成所有单词的列表。 然后过滤该列表,以便仅保留重复的单词。 可以使用… | sort | uniq -d
进行过滤… | sort | uniq -d
… | sort | uniq -d
… | sort | uniq -d
最后,从先前使用grep -Fwvf listFile inputFile
生成的列表中打印不包含任何单词的所有行。
在bash
所有这些步骤都可以在一个命令中运行。 在这里,我们将使用变量$in
使其易于适应。
in="path/to/your/input/file"
grep -Fwvf <(grep -Eo '[^ ]+' "$in" | sort | uniq -d) "$in"
使用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
存储在由记录号NR
索引的数组record
record
以及当前记录中删除原始记录。 如果尚未看到,请将单词和当前记录号存储在seeed数组seen
。 record
的索引,则打印该记录。 $ 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
这适用于您的示例:
#!/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
| sort
排序列表 | uniq -d
| uniq -d
仅输出连续出现多次的单词 然后使用sed
选择并删除所有包含重复单词的行。
这可能适合您(GNU grep,sort,uniq,sed):
sed 's/ /\n/g' file | sort |uniq -d | grep -vFf - file
或玩具GNU sed解决方案:
cat <<\! | sed -Ef - file
H # copy file into hold space
$!d # delete each line of the original file
g # at EOF replace pattern space with entire file
y/ /\n/; # put each word on a separate line
# make a list of duplicate words, space separated
:a;s/^(.*\n)(\S+)(\n.*\b\2\b)/\2 \1\3/;ta
s/\n.*// # remove adulterated file leaving list of duplicates
G # append original file to list
# remove lines with duplicate words
:b;s/^((\S+) .*)\n[^\n]*\2[^\n]*/\1/;tb
s/^\S+ //;tb # reduce duplicate word list
s/..// # remove newline artefacts
!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.