假设我有一个包含以下内容的文件:
VSDmaMapInfo
VSDmaMapInfo::
VSDmaMapInfo;
VSPortErr
VSPortErr,
VSPortErr::
排序后我希望输出为
VSDmaMapInfo
VSPortErr
有没有办法使用 grep、awk、uniq 或任何其他工具等
非常感谢你的帮助。
假设我有一个包含以下内容的文件:
VSDmaMapInfo
VSDmaMapInfo::
VSDmaMapInfo;
VSPortErr
VSPortErr,
VSPortErr::
排序后我希望输出为
VSDmaMapInfo
VSPortErr
有没有办法使用 grep、awk、uniq 或任何其他工具等
非常感谢你的帮助。
$ awk -F'[[:punct:]]' '{print $1}' file | sort -u
VSDmaMapInfo
VSPortErr
使用 GNU sed 排序内容的代码
sed -r '$!N;/(\w+)\W*\n\1\W*/!{s/(\w+).*/\1/;P};D' file
这可以工作:
$ tr -d "[[:punct:]]" < file | sort -u
VSDmaMapInfo
VSPortErr
tr -d "[[:punct:]]" < file | sort -u
remove puntuation chars read file get unique
从您的评论中:
我刚刚观察到:如果输入包含 VSDmaMapInfo::callMe,它会删除标点符号,但会加入下一个单词,例如 VSDmaMapInfocallMe。是否有可能我只将输出作为 VSDmapMapInfo 而没有附加下一个单词。
我们可以做到以下几点:
$ cat file
VSDmaMapInfo
VSDmaMapInfo::
VSDmaMapInfo;
VSDmaMapInfo;asdfs
VSPortErr
VSPortErr,
VSPortErr::
$ awk -F"[,:;]" '{print $1}' file | sort -u
VSDmaMapInfo
VSPortErr
也就是说,打印awk
any或之前的第一个单词。然后,使用参数对其进行排序以获得唯一数据。,
:
;
-u
假设重复数据删除不区分大小写,以下 Perl-oneliner 会发出所需的输出:
perl -ne's/[[:punct:]]+$//;$h{lc $_}++ or print'
测试:
$ perl -ne's/[[:punct:]]+$//;$h{lc $_}++ or print' <<'END'
VSDmaMapInfo
VSDmaMapInfo::
VsDmaMapInfo;
VSPortErr
VsPortErr,
VsPortErr::
END
输出:
VSDmaMapInfo
VSPortErr
对于区分大小写的匹配更改$h{lc $_}++
为$h{$_}++
.
要删除行上第一个标点字符之后的任何内容,请将替换替换为s/[[:punct:]].*//
.
要使用文件调用单行程序,您可以将输入文件列为命令行参数:
$ perl -ne'...' the-file.txt
sed 解决方案(基本上是 sed + sort)
sed 's/[^[:alpha:]]//g' <file> |sort -u
另一个笨拙的 awk 解决方案
awk '{gsub(/[^[:alpha:]]/,""); a[$0]=1} END{for(var in a) print var}' <file>
另一个很棒的纯 bash 解决方案(我喜欢玩 bash :))
l=""
while read r
do
r=${r//[^[:alpha:]]/}
if ! [[ $l =~ $r ]]
then
echo $r
l="$l $r"
fi
done < <file>
如果您使用 GNU awk
,您可以使用多个字符作为记录分隔符 ( RS
),因此您可以这样做:
awk '!a[$0]++' RS='[[:punct:]]*\n' test.txt
解释:
RS
) 设置为此正则表达式,我们摆脱了尾随标点符号,因此记录 ie$0
是一个单词。a
。
a[$0]
为 0,并且!a[$0]
计算结果为真,则该单词被打印出来。否则,它不会被打印出来。跳过重复的行,
perl -nE 's|\W||g; say unless $h{$_}++' file