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

Linux 为什么这个行号命令会破坏字符编码?,linux,perl,encoding,Linux,Perl,Encoding,我想通过在每行的开头添加行号来修改文件。我发现以下命令可以执行此操作: cat文件| perl-pe'$\=“$.$\'>带有行数的文件 但是,这似乎是可行的,当我在vim中打开文件时,它充满了^@和^M字符。进一步的调查表明编码已经改变 > file -bi file text/plain; charset=utf-16le > file -bi file_with_line_numbers application/octet-stream; charset=binary 我在

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

cat文件| perl-pe'$\=“$.$\'>带有行数的文件

但是,这似乎是可行的,当我在vim中打开文件时,它充满了^@和^M字符。进一步的调查表明编码已经改变

> file -bi file
text/plain; charset=utf-16le

> file -bi file_with_line_numbers
application/octet-stream; charset=binary

我在这里遗漏了什么?

因为您没有解码输入数据,也没有对输出数据进行编码,并且通过将
$。
$连接,您混合了两种不同编码的数据(相反,您混合了字节字符串和字符串,但是perl隐式地将字节字符串转换为字符串,并且按照您的需要以非常错误的方式进行转换)

一个解决办法是:

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

您需要对程序的输入进行解码,并对程序的输出进行编码

正如ysth所指出的那样,这将达到目的(除了在Windows上,但可能使用cygwin):


原始答案的其余部分:

如果您有UTF-8,这是最容易做到的,因为您可以使用
-CSDA

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

file.out

你可以直接使用nl。这就是它的用途。
nl file>new\u file\u带有行数
@squiguy,不,
nl
将以完全相同的方式失败。解释让我开始了,但我最终得到的代码与@ikegami提交的答案几乎相同。我没有尝试过,但不会
perl-Mopen=:std,:e编码(utf-16le)“…
work?你的意思是如果你在@ARGV中提供输入文件?嗯;我以为open.pm编码在某个时候不适用于ARGV,但后来得到了修复,但我只是在5.8.8和5.14.2上进行了尝试,这两个版本似乎都很好!刚刚验证过。这很好。在Windows上不起作用,因为:crlf的顺序不正确,但OP似乎使用unix(cygwin?),更新答案。
<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