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

cac*_*ce7 4 linux perl encoding

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

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
Run Code Online (Sandbox Code Playgroud)

我在这里错过了什么?

hob*_*bbs 9

因为你没有解码输入数据,你就不是你的编码输出数据,并通过连接$.$_你混合是在两个不同的编码(更确切地说,你混合字节字符串,字符串数据,但perl隐式地将字节字符串转换为字符串,并以非常错误的方式为您所需要的方式执行此操作.

一个解决方案是:

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


ike*_*ami 5

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

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

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

其余的原始答案:

如果您有UTF-8,这是最容易完成的,因为您可以使用它-CSDA.

<file.in iconv -f UTF-16le -t UTF-8 \
   | perl -CSDA -pe'$_="$. $_";' \
     | iconv -f UTF-8 -t UTF-16le \
       >file.out
Run Code Online (Sandbox Code Playgroud)

由于UTF-8的属性,在这种情况下您可以完全脱离而无需解码/编码,允许您使用以下任一方法:

<file.in iconv -f UTF-16le -t UTF-8 \
   | perl -pe'$_="$. $_";' \
     | iconv -f UTF-8 -t UTF-16le \
       >file.out
Run Code Online (Sandbox Code Playgroud)

要么

<file.in iconv -f UTF-16le -t UTF-8 \
   | nl \
     | iconv -f UTF-8 -t UTF-16le \
       >file.out
Run Code Online (Sandbox Code Playgroud)