2013-01-02 47 views
4

我想通过在每行的开头添加行号来修改文件。我发现下面的命令做到这一点:为什么此行编号命令会破坏字符编码?

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 

我在这里错过了什么?

+1

你可以使用nl。这是它的目的。 'nl file> new_file_with_line_numbers' – squiguy

+0

@squiguy,Nope,'nl'将会以完全相同的方式失败。 – ikegami

回答

5

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

由于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 
+0

还没有尝试过,但不会'perl -Mopen =:std,:encoding'(utf-16le)'...'工作? – ysth

+0

你是说如果你在@ARGV中提供输入文件? – ysth

+0

呵呵;我认为open.pm编码在某些时候并不适用于ARGV,但后来被修复了,但我只是尝试了5.8.8和5.14.2,两者似乎都可以工作 – ysth

9

因为您没有解码输入数据,也没有对输出数据进行编码,并且通过将$.$_连接在一起,您将混合使用两种不同编码的数据(相反,字符串和一个字符串,但是perl会隐式地将字节串转换为一个字符串,并以非常错误的方式处理您需要的内容)。

一个补丁修复是:

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

@ikegami很好的电话。让我解决它。 – hobbs

+0

这个解释让我开始了,但是我最终得到的代码与@ikegami提交的答案几乎完全相同。 – cachance7