我有一个 300 行的文件,^@
文件中每个字符之间都有字符。
(出于安全原因,我无法发布全部内容,所以我只粘贴第一行)
[mercury@app01 ftp_logs]$ cat cl.txt
2015-01-22 03:00:01; local;
现在,当我查看vi
文件时,我会看到以下相同的内容:
2^@0^@1^@5^@-^@0^@1^@-^@2^@2^@ ^@0^@3^@:^@0^@0^@:^@0^@1^@;^@ ^@l^@o^@c^@a^@l^@;^@
由于cat
没有显示^@
字符,我自然认为 grep 某个字符串可以在 中工作cat
,但令人惊讶的是,事实并非如此。
[mercury@app01 ftp_logs]$ cat cl.txt
2015-01-22 03:00:01; local;
[mercury@app01 ftp_logs]$ cat cl.txt | grep local
[mercury@app01 ftp_logs]$
用 替换空字节后sed
,文件现在可以在 中读取vi
并grep
从 中返回结果cat
。
[mercury@app01 ftp_logs]$ sed -i 's/\x0//g' cl.txt
[mercury@app01 ftp_logs]$ cat cl.txt | grep local
2015-01-22 03:00:01; local;
[mercury@app01 ftp_logs]
问题:
1) 为什么grep
在替换空字节之前不起作用,因为空字节没有被显示。这是否意味着即使终端中没有显示grep
这些字符也看到了?^@
2)这让我想知道是否建议在生产服务器上使用cat -v
或vi
读取文件,因为cat
似乎可以很好地隐藏东西?
3) 相关文件是 Windows 计算机自动生成的文件。在什么情况下会^@
进入文件。
答案1
文件的格式可能是小端 UTF-16。 Windows 上的一些应用程序似乎默认这样做,这会导致很多可移植性问题。
vi
将 ASCII-Nul(数字零)值字节表示为“^@”(control-At)。实际上,您可以vim
使用 control-shift-@ 和弦输入零值字节。
grep
必须查看 ACII-Nul 字节,而不是将文件解释为 UTF-16,然后查看“2”或“0”等的 Unicode 代码点。我在 GNU 手册页中没有看到grep
让它处理 UTF-anything 的选项。
cat
不显示 ASCII-Nul btyes,有问题的终端仿真器会显示它们,但无论您使用什么终端仿真器都会忽略它们。如果您使用cat cl.txt | od -x
或更好的cat cl.txt | xxd
,您将在 的输出中看到 ASCII-Nul 字节cat
。如果您在文件的前两个字节中看到类似“ffef”或“efff”的内容,则这些是 Microsoft 违反所有常识颁布的“字节顺序标记”。
我不确定应该推荐什么来将 UTF-16 音译为 ASCII 或 UTF-8,iconv
但我从未使用过它。
答案2
是的,
grep
交换^@
角色。cat
正在将字符打印到终端,但它们是您看不到的字符。仅仅因为您看不到这些角色并不意味着它们不存在。您的选择/偏好,取决于哪一种最适合您的需求。但请记住,这
vi
有可能更改文件。^@
不是天生的性格。 Windows 程序正在主动将这些字符放在那里。要找出原因,你必须询问程序员。最有可能的是,Windows 程序假设字符为 16 位宽,而 Unix 机器则假设字符为 8 位宽。
答案3
我曾经也有过一样的问题。
vi
了解文件字符集。
如果你使用
file c1.txt
您可以查看它是 UTF-8 还是 ISO 文件。
之后,您可以使用转换实用程序将其转换
echo file iso-8859-1 is converted to UTF in order to be emailed
iconv -f 'iso-8859-1' -t UTF-8 $MESGFILE >> $MESGENVIADO