echo和wc是shell里非常常用的两个命令。echo用来输出文本,wc用来计数。默认wc会显示3个结果:行数,单词数,字节数。

来看这样一句命令:

$ echo "1" | wc

输出会是什么呢?

一开始,我的答案是:

1 1 1

一行,一个单词,一个字节嘛。然而我被结结实实的打脸了,因为输出是:

1 1 2

为什么是2个字节呢?即使是utf-8也应该是1个字节吧。试试增加一个字符的情况:

$ echo "12" | wc
1 1 3

添加了一个字符后,字节数也增加了1。也就是说明一个ASCII字符的确是一个字节。那么问题来了,为什么字节数会多一个呢?

查看了echo的man文档,傻了眼,echo默认是会输出换行的!也就是默认就会输出一个字符。这个行为竟然一直被我忽视了。。。

1
2
3
$ echo ""
$

使用-n参数,可以使echo不默认追加换行:

1
2
$ echo -n ""
$

所以回过头来,使用wc:

1
2
$ echo -n "1" | wc
0 1 1

这下字节数对了。但是,怎么变成0行了啊。。。

也是查看了wc的文档,wc对于一行的定义是带有换行符结尾的字符串算是一行。所以上面这个例子因为只输出了不带换行的内容,所以wc认为是0行。

想想,那如果用wc统计文本,不是很容易出现少一行的情况么?因为文本的最后一行不一定会带有换行符的。

百度一下linux wc 少一行,果然有许多人问这个问题。linux中遇到的会少一些,因为像是vim这样的工具,会默认在会后一行追加换行符的。细想,也就明白了为什么有些代码风格里,竟然会要求文件最后得有一个空行,或许和这个有些关系吧。

最后说一下echo和wc的详细参数吧。

echo的参数:

  • -n 不最追加显示换行符
  • -e 对文本中的转义字符进行转义
  • -E 不对文本中的转义字符进行转义(默认开启)

需要注意的是,linux下,echo默认不会对字符串进行转义。而mac中(应该是Unix中),echo默认会对字符串转义,而且也米有-e-E这两个选项(也就是不能禁止echo转义)。这个区别可不太好啊,编写跨平台脚本的时候需要注意了。

wc的参数:

  • -c 显示字节数
  • -m 显示字符数
  • -l 显示行数(其实是换行符数)
  • -w 显示单词数
  • -L 显示最长一行的长度(Unix中没有)
  • --files0-from=file 从文件或者标准输入中读入文件名,文件名以\0分隔。(Unix中没有)

其中--files0-from=file可以这么用:

find . -name '*.[ch]' -print0 | wc -L --files0-from=- | tail -n1