我使用awk
命令来计算具有相同开头的行...
例如,在try1.txt
中,文本为:
b : c
b : c
当我在终端中启动以下命令时:
awk -F ' : ' '$1=="b"{a[$2]++} END{for (i in a) print " ", i,a[i]}' try1.txt
它会返回c 2
,这很好,因为b : c
在try1.txt
中出现两次。
我的工具的输出是一个巨大的output.txt
,比try1.txt
复杂得多。 output.txt
的某些部分包含以下字符:
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^137
当进程被杀死时,系统会系统地编写它。我很好。但是,我意识到它会阻止awk
运作良好。例如,在try2.txt
中如下:
b : c
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^137
b : c
命令awk -F ' : ' '$1=="b"{a[$2]++} END{for (i in a) print " ", i,a[i]}' try2.txt
返回c 1
。也就是说,当它遇到奇数行^@^@^@^@^@
时停止了。
我不知道如何防止系统写入奇数行^@^@^@^@^@
,所以有谁知道如何修改awk
命令来解决?
修改:我在^@
中找到的output.txt
似乎不是普通字符^@
。以下是output.txt
屏幕截图的一部分,显示在Emacs
,但有问题:
修改:根据建议,我运行了xxd try2.txt
,它提供了:
0000000: 6220 3a20 630a 0000 0000 0000 0000 0000 b : c...........
0000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000020: 0000 0000 0000 0000 0031 3337 0a62 203a .........137.b :
0000030: 2063 0a
答案 0 :(得分:2)
^@
可能代表二进制0 / NUL字符:
$ head -c10 /dev/zero > 10zero $ cat -v 10zero ^@^@^@^@^@^@^@^@^@^@$
某些面向文本的实用程序可能会将此视为文件末尾。
因此,由于您的输入文件是二进制文件,因此您应该先从中提取文本字符串,然后再对其进行操作:
$ strings try1.txt | awk -F ' : ' '$1=="b"{a[$2]++} END{for (i in a) print " ", i,a[i]}'
c 2
$
The strings
command man page.(顺便提一下,当你google" man strings" - 你可能会得到一些你可能没有讨价还价的图像;-))
注意好奇 - 我在我的机器上完全重新创建了OP的try1.txt文件:
xxd
输出捕获到名为try1.xxd xxd -r try1.xxd > try1.txt
reverses the normal xxd
operation。答案 1 :(得分:2)
许多Awk实现和一般的Unix文本处理工具处理空(零)字节的效果很差,因为它是用于构建这些工具的基本C库的字符串结束终止符。
Perl旨在处理任意输入;您可以尝试a2p
将您的Awk脚本转换为Perl(但不要指望惯用,可维护或高效的Perl)。
或试试这个;
perl -lne '$a{$1}++ if (/^b : (.*?)\s*$/);
END { for $i (keys %a) { print " ", $i, " ", $a{$i} } }' try1.txt
答案 2 :(得分:1)
如果您想要的所有行都包含:
,则可以尝试将$0 ~ /:/
作为选择器。这是新的和改进的 awk语句(我在不同的行上写了它,因为它更容易跟踪花括号:
$ awk -F ' : ' '
{
if ( $0 ~ /:/ && $1 == "b" ) {
a[$2]++
}
}
END {
for (i in a) {
print " ", i,a[i]
}
}' try.txt
只要^@
在他们自己的行上,这就有效。如果没有,您必须找出^@
的字符类型。我怀疑它是一个空字符。如果是这样,您可能必须从文件中删除它们:
$ tr -d \0 < try.txt > try2.txt
这应该删除那些烦人的角色。然后,使用try2.txt
进行输入。