为什么这行编号命令破坏字符编码?

我想通过在每行的开头添加行号来修改文件。 我发现以下命令执行此操作:

cat file | perl -pe '$_ = "$. $_"' > file_with_line_numbers

这似乎工作,但是,当我在vim中打开文件它充满^ @和^ M字符。 进一步的调查显示编码已经改变。

 > file -bi file text/plain; charset=utf-16le > file -bi file_with_line_numbers application/octet-stream; charset=binary 

我在这里错过了什么?

你需要解码你的程序的输入和编码你的程序的输出。

正如ysth指出,这将做的伎俩(Windows除外,但可能使用cygwin):

 perl -Mopen=:std,':encoding(utf-16le)' -pe'$_="$. $_";' file.in >file.out 

其余的原始答案:

如果你有UTF-8,最简单的方法是完成,因为你可以使用-CSDA

 <file.in iconv -f UTF-16le -t UTF-8 \ | perl -CSDA -pe'$_="$. $_";' \ | iconv -f UTF-8 -t UTF-16le \ >file.out 

由于UTF-8的属性,在这种情况下,您可以完全脱离解码/编码,使您可以使用以下任一项:

 <file.in iconv -f UTF-16le -t UTF-8 \ | perl -pe'$_="$. $_";' \ | iconv -f UTF-8 -t UTF-16le \ >file.out 

要么

 <file.in iconv -f UTF-16le -t UTF-8 \ | nl \ | iconv -f UTF-8 -t UTF-16le \ >file.out 

因为你没有解码你的输入数据,也没有编码你的输出数据,并且连接了$.$_来混合使用两种不同编码的数据(而不是混合一个字节串和一个字符串,但是perl会隐式地把字节串转换成一个字符串,方式为你所需要的)。

一个解决办法是:

 perl -pe 'BEGIN { binmode STDIN, ":encoding(utf16le)"; binmode STDOUT, ":encoding(utf16le)" } $_ = "$. $_";' < input > output