“grep -c”与“wc -l”的区别

8
我正在处理一些大型文本文件,即将它们从一种格式转换为另一种格式。这些文件的原始格式有些小差异,但是在一些情况下进行预处理后,它们大多数都可以通过我创建的Bash shell脚本成功转换。
到目前为止一切都很好,但有一件事让我感到困惑。在某个时候,脚本设置了一个名为$iterations的变量,以便它知道执行特定for循环的次数。这个值是由脚本创建的临时文件中的空行数确定的。
因此,我的脚本的原始版本包含了以下行:
    iterations=$(cat tempfile | grep '^$' | wc -l)

到目前为止,这种方法在除了一个文本文件外的所有文本文件中都运行良好。这个文本文件似乎没有正确设置$iterations变量,即使tempfile中有超过20,000个空行,也会给出一个值为'1'的结果。

然而,我发现了grep -c命令后,将这一行改为:

    iterations=$(cat tempfile | grep -c '^$')

脚本突然工作了,即$iterations正确设置。

有人能解释一下为什么这两个版本会产生不同的结果吗?为什么第一个版本在某些文件上可以工作而在其他文件上不能工作?是否有某个上限值,超过该值wc -l默认为1?第一个版本无法处理的文件是其中最大的文件之一,但不是最大的文件(最大的文件第一次转换时已经正确)。


2
你能复制这个吗?也就是说,你有一个文件吗,grep -c'^$' 产生的输出与 grep '^$' | wc -l 不同? - William Pursell
我想知道文件是否包含一些有趣的内容,会让 wc 感到困惑。如果运行 cat tempfile | grep '^$' | hexdump -C | head,会产生什么有趣的结果吗? - Dima Chubarov
2
printf 'foo\nbar\n\x00\n\n\n\n' | { cat > /tmp/file; grep -c '^$' < /tmp/file; grep '^$' < /tmp/file | wc -l; } Dmitri已经解决了。使用空字符, wc产生1,而grep -c则计算为4。 - William Pursell
2
当然,问题在于grep正在打印“Binary file (standard input) matches”,而wc正在计算该行! - William Pursell
另一个原因可能是grep 2.13错误地将某些文件视为二进制文件,例如存储在实现重复数据删除的文件系统上的大文件。这在2.14 (git log)及更高版本中得到了纠正。 - Dima Chubarov
1个回答

11

如果输入不是文本文件,则 grep 将打印单行 Binary file (standard input) matcheswc -l 将计算该行数!但是 grep -c 将愉快地计算文件中的匹配数。


@dmitri:我明白了(我想)......在那个大文本文件中,一定有一个幸运的字符序列,grep(没有 -c)将其解释为空字符?我从未想过这一点。我从未遇到过空字符;我猜它一定有用处。 :-) - John W
1
不一定是空字符。它可以是任何使grep将文件视为二进制文件的字符。 - William Pursell

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