2013-01-02 48 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