如何使用Linux命令行工具列出文本文件中使用的唯一字符?

10
我想使用Linux命令行工具列出文本文件中使用的一组字符。我该如何实现?
唯一的实用程序uniq 只能在行上操作。

这似乎是 awk 的任务:awk 'BEGIN{FS=""} {for(i=1;i<=NF;i++){chars[$(i)]=$(i);}} END{for(c in chars){print c;} }' 或者 awk 'BEGIN{FS=""} {for(i=1;i<=NF;i++) print $(i);};' file.txt | sort | uniq - user184968
这个有效 :) 你可以将其发布为答案并解释一下吗? - Patryk
3个回答

13

我会使用od

od -cvAnone -w1

这个列表展示了字符,并显示了非可见字符的\escapes。其他格式可用


示例:

因此,要列出独特项:

od -cvAnone -w1 | sort -bu

或者生成一个前20的直方图:

od -cvAnone -w1 | sort -b | uniq -c | sort -rn | head -n 20

IdeOne 上实时查看。


我稍微修改了一下,以便在结尾处使用“| sort -u”,这样我就可以在单个文件中看到所有字符的一个代表。 - delliottg
@delliottg,你的评论让我觉得很有趣,因为 | sort -bu 已经在我的答案中展示了 :) - sehe
1
哈哈,完全错过了,不知道怎么回事,我只是很兴奋地在我的CYGWIN实例中让od -cvAnone -w1工作,然后我将其唯一排序(这正是我所需要的),然后回到这里点赞和评论,所有这些都没有阅读你帖子的其余部分(直到现在)。 - delliottg
使用 od -cvAnone -w1 <<< défaillir 命令输出的结果与预期不符。 - Alexx Roche

8
我更喜欢使用这种方式:
awk 'BEGIN{FS=""} {for(i=1;i<=NF;i++){chars[$(i)]=$(i);}} END{for(c in chars){print c;} }'

因此,这个脚本是一个awk脚本。awk对各种命令输出的处理非常有用。

这个脚本分为三部分:

  • BEGIN,在处理之前只执行一次
  • END,在处理之后执行
  • 中间有一个循环来处理输出

1)

BEGIN{FS=""} 

从这里开始http://www.gnu.org/software/gawk/manual/html_node/Field-Splitting-Summary.html#Field-Splitting-Summary

FS == "" 每个记录中的每个字符都成为一个单独的字段。(这是gawk的扩展功能; 它没有被POSIX标准规定。)

2)

{for(i=1;i<=NF;i++){chars[$(i)]=$(i);}}
chars是一个一维关联数组(参见http://www.gnu.org/software/gawk/manual/html_node/Array-Basics.html#Array-Basics)。在处理每个字符时,我会向其中添加值。
END{for(c in chars){print c;} }

最后一部分 - 遍历整个数组chars并打印其索引。 http://www.gnu.org/software/gawk/manual/html_node/Scanning-an-Array.html#Scanning-an-Array PS.
关于@sehe的处理方式。 寻找一个比较大的文本文件。使用关联数组会快六倍:
>time od -cvAnone -w1 vector.html.big | sort -bu > /dev/null

real    0m1.597s
user    0m1.619s
sys     0m0.022s

>time awk 'BEGIN{FS=""} {for(i=1;i<=NF;i++){chars[$(i)]=$(i);}} END{for(c in chars){print c;} }' vector.html.big | sort >/dev/null

real    0m0.252s
user    0m0.251s
sys     0m0.002s

在时间方面:输入有点关键;从结果看,awk 看起来比较快,大约是全二进制数据的4到6倍(与仅限 a..z 的数据相比)。 - sehe
有趣的是,当使用C语言环境时,很多差异都消失了:完整二进制仅a..z,两者之间只有大约2倍的差异。 - sehe

0
这里有一种Perl的方法,它会打印出Unicode代码点和字符本身:
perl -C7 -ne 'for (split(//)) {print sprintf("U+%04X", ord)." ".$_."\n"}' $Your_File | sort -u

或者为了易读性,可以分多行显示:
perl -C7 -ne 'for ( split(//) ) {
    print sprintf("U+%04X", ord) . " " . $_ . "\n"
    }' $Your_File \
| sort -u

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接