分享幾個在Windows 與Linux 常見的編碼問題與解決方案
文章推薦指數: 80 %
看到上述這麼多支援的編碼不同,而跙Windows PowerShell 5.1 以前的版本竟然沒辦法指定UTF8 (No BOM) 的輸出,實在母湯!👎.
←使用luit完美解決WindowsSubsystemforLinux顯示Big5字集的問題
使用VisualStudioCode開發Java應用程式的環境設定指南→
我每隔幾年我就會遇到一次non-Unicode的編碼問題,真的不常見,但這些年來也處理過無數次了,每次都被搞的很煩。
最近在Linux環境又遇到棘手的編碼問題,檔案內容是從ISO-8859-1(Latin-1)字集的SybaseASE資料庫轉出,所以編碼是ISO-8859-1字集,但內容其實是BIG5字集,而我用WindowsTerminal+WSL2又只支援顯示Unicode字集的文字,所以文字無法正常在螢幕上顯示或複製。
幾經嘗試後,我決定把這幾年累積的心得都寫下來,以免日後又要再花時間研究一次。
準備一個有文字編碼問題的環境
我準備了一個以BIG5編碼的文字檔案,請先在任意Windows與Linux環境下載:
Linux
curlhttps://blog.miniasp.com/big5-example.txt-obig5-example.txt
我這邊的Linux版本為:
$lsb_release-a
NoLSBmodulesareavailable.
DistributorID:Ubuntu
Description:Ubuntu20.04.2LTS
Release:20.04
Codename:focal
WindowsPowerShell
Invoke-WebRequest-Urihttps://blog.miniasp.com/big5-example.txt-OutFilebig5-example.txt
❯$PSVersionTable
NameValue
---------
PSVersion5.1.19041.1023
PSEditionDesktop
PSCompatibleVersions{1.0,2.0,3.0,4.0...}
BuildVersion10.0.19041.1023
CLRVersion4.0.30319.42000
WSManStackVersion3.0
PSRemotingProtocolVersion2.3
SerializationVersion1.1.0.1
PowerShellCore
❯$PSVersionTable
NameValue
---------
PSVersion7.1.3
PSEditionCore
GitCommitId7.1.3
OSMicrosoftWindows10.0.19043
PlatformWin32NT
PSCompatibleVersions{1.0,2.0,3.0,4.0…}
PSRemotingProtocolVersion2.3
SerializationVersion1.1.0.1
WSManStackVersion3.0
Windows命令提示字元(CommandPrompt)
基本上,在Windows命令提示字元環境下,編碼問題可以很輕易的透過CHCP命令(C:\Windows\System32\chcp.com)快速切換,只要你設定的字型有支援這個字集,就可以正常顯示文字在畫面上。
我的Windows10控制台的地區設定(Regionsettings)指定的non-Unicode字集為Chinese(Traditional,Taiwan),這個設定會讓你的命令提示字元預設CodePage為950,也就是俗稱的Big5編碼。
在CommandPrompt環境下,預設可以正常輸出Big5編碼的文字:
你可以透過以下命令快速切換為使用Unicode作為預設編碼:
chcp65001
或是透過以下命令快速切換回預設的CP950(Big5)編碼:
chcp950
Windows命令提示字元在編碼處理上一致性很高,而且切換字集很容易,不太有什麼地雷。
WindowsPowerShell與PowerShellCore的預設編碼差異
基本上PowerShell可以區分5.1以前的版本與6.0之後的版本,兩個版本對於預設字集的處理方式不同,必須認真看待,否則執行同一個PowerShellScript並不會得到相同的結果。
使用BOM(byte-order-mark)字元的差異
PowerShellScript(.ps1)本身的內容,其實也影響著PowerShell的執行結果:
比較項目
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
檔案內容使用ANSI編碼(ASCII)
會直接視為ANSI字集
會直接視為UTF8字集
檔案內容使用UTF8編碼(NoBOM)
會直接視為ANSI字集
會直接視為UTF8字集
檔案內容使用UTF8編碼(BOM)
會直接視為UTF-8字集
會直接視為UTF8字集
如果你要在PowerShellScript中使用到non-ascii字元(例如:中文字),請務必加上BOM字元,因為Windows有時候會誤判檔案字集,如果誤判為ANSI字集的話,這些文字就會亂掉,導致PowerShellScript無法正確執行。
相反的,在Linux作業系統中,如果你加入BOM字元的話,可能會導致一些未知的問題,所以建議不要加上BOM字元。
總之,你真的想用PowerShellScript來撰寫跨平台的自動化命令腳本,不要寫中文在腳本中。
我是完全不考慮在Linux使用PowerShell了啦!XD
字元編碼處理的差異
比較項目
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
預設輸出使用的編碼
UnicodeUTF-16LE
utf8NoBOM
注意:基本上UTF-16以上的文字編碼,都會強制要求一定要有BOM字元,只有UTF-8可以選擇要不要加上BOM字元。
可以指定Encoding的Cmdlets
以下是包含-Encoding參數的Cmdlets清單,可以讓你用指定的Encoding處理文字:
Microsoft.PowerShell.Management
Add-Content
Get-Content
Set-Content
Microsoft.PowerShell.Utility
Export-Clixml
Export-Csv
Export-PSSession
Format-Hex
Import-Csv
Out-File
Select-String
Send-MailMessage
這個-Encoding參數支援的編碼對照
字集
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
Default(ANSI)
✅(Default)
❌
OEM(作業系統預設)
✅(Oem)
✅(oem)
ASCII(7-bit)字集
✅(Ascii)
✅(ascii)
UTF7
✅(UTF7)
✅(utf7)
UTF8(NoBOM)
❌
✅(utf8)
UTF8(NoBOM)
❌
✅(utf8NoBOM)
UTF8BOM
✅(UTF8)
✅(utf8BOM)
UTF-16BEBOM
✅(BigEndianUnicode)
✅(bigendianunicode)
UTF-16LEBOM
✅(String)
❌
UTF-16LEBOM
✅(Unicode)
✅(unicode)
UTF-16LEBOM
❌(官網有寫但不能用)(Unknown)
❌
UTF-32BEBOM
❌(官網有寫但不能用)(BigEndianUTF32)
✅(官網沒寫這項但實際上有)(bigendianutf32)
UTF-32LEBOM
✅(UTF32)
✅(utf32)
Bytes
❌(官網有寫但不能用)(Byte)
❌
看到上述這麼多支援的編碼不同,而跙WindowsPowerShell5.1以前的版本竟然沒辦法指定UTF8(NoBOM)的輸出,實在母湯!👎
PowerShellCore6.0之後的版本,可用的編碼比文件上寫的多出很多,你可以用以下命令查詢出當前系統可用的編碼清單:
❯[System.Text.Encoding]::GetEncodings()
CodePageNameDisplayName
-----------------------
932shift_jisshift_jis
860IBM860IBM860
861ibm861ibm861
20880IBM880IBM880
862DOS-862DOS-862
863IBM863IBM863
936gb2312gb2312
864IBM864IBM864
865IBM865IBM865
866cp866cp866
21866koi8-ukoi8-u
37IBM037IBM037
869ibm869ibm869
500IBM500IBM500
10079x-mac-icelandicx-mac-icelandic
1140IBM01140IBM01140
1141IBM01141IBM01141
1142IBM01142IBM01142
20273IBM273IBM273
1143IBM01143IBM01143
1144IBM01144IBM01144
1145IBM01145IBM01145
1250windows-1250windows-1250
1146IBM01146IBM01146
1251windows-1251windows-1251
1147IBM01147IBM01147
10000macintoshmacintosh
1252windows-1252windows-1252
720DOS-720DOS-720
20277IBM277IBM277
1148IBM01148IBM01148
10001x-mac-japanesex-mac-japanese
1253windows-1253windows-1253
437IBM437IBM437
20278IBM278IBM278
1149IBM01149IBM01149
10002x-mac-chinesetradx-mac-chinesetrad
1254windows-1254windows-1254
1255windows-1255windows-1255
1361JohabJohab
1256windows-1256windows-1256
10004x-mac-arabicx-mac-arabic
1257windows-1257windows-1257
10005x-mac-hebrewx-mac-hebrew
1258windows-1258windows-1258
10006x-mac-greekx-mac-greek
10007x-mac-cyrillicx-mac-cyrillic
20924IBM00924IBM00924
28592iso-8859-2iso-8859-2
28593iso-8859-3iso-8859-3
28594iso-8859-4iso-8859-4
28595iso-8859-5iso-8859-5
28596iso-8859-6iso-8859-6
870IBM870IBM870
28597iso-8859-7iso-8859-7
28598iso-8859-8iso-8859-8
28599iso-8859-9iso-8859-9
10081x-mac-turkishx-mac-turkish
10082x-mac-croatianx-mac-croatian
874windows-874windows-874
875cp875cp875
20420IBM420IBM420
949ks_c_5601-1987ks_c_5601-1987
20423IBM423IBM423
20424IBM424IBM424
20280IBM280IBM280
1047IBM01047IBM01047
20284IBM284IBM284
20285IBM285IBM285
10010x-mac-romanianx-mac-romanian
20932EUC-JPEUC-JP
10017x-mac-ukrainianx-mac-ukrainian
29001x-Europax-Europa
737ibm737ibm737
20105x-IA5x-IA5
950big5big5
20936x-cp20936x-cp20936
20106x-IA5-Germanx-IA5-German
20107x-IA5-Swedishx-IA5-Swedish
20108x-IA5-Norwegianx-IA5-Norwegian
20866koi8-rkoi8-r
775ibm775ibm775
28603iso-8859-13iso-8859-13
20290IBM290IBM290
28605iso-8859-15iso-8859-15
20000x-Chinese-CNSx-Chinese-CNS
708ASMO-708ASMO-708
20297IBM297IBM297
10021x-mac-thaix-mac-thai
20001x-cp20001x-cp20001
20905IBM905IBM905
20002x-Chinese-Etenx-Chinese-Eten
20833x-ebcdic-koreanextendedx-ebcdic-koreanextended
20003x-cp20003x-cp20003
20004x-cp20004x-cp20004
20005x-cp20005x-cp20005
850ibm850ibm850
20838IBM-ThaiIBM-Thai
852ibm852ibm852
20871IBM871IBM871
10029x-mac-cex-mac-ce
855IBM855IBM855
21025cp1025cp1025
20949x-cp20949x-cp20949
857ibm857ibm857
858IBM00858IBM00858
20261x-cp20261x-cp20261
1026IBM1026IBM1026
20269x-cp20269x-cp20269
1200utf-16Unicode
1201utf-16BEUnicode(Big-Endian)
12000utf-32Unicode(UTF-32)
12001utf-32BEUnicode(UTF-32Big-Endian)
20127us-asciiUS-ASCII
28591iso-8859-1WesternEuropean(ISO)
65001utf-8Unicode(UTF-8)
不過WindowsPowerShell5.1以前的版本,地雷的地方還不只這些,不同的Cmdlet實作上對「預設編碼」的選用並不一致,並非所有預設都以UTF-16LEBOM編碼為主。
關於重新導向運算子(Redirectionoperators)(>、>>)的預設編碼
從WindowsPowerShell5.1開始,預設所有>與>>導向都會委由Out-FileCmdlet處理,這也意味著預設輸出編碼是可以調整的,這部分在本文後續會提及。
但在這之前的WindowsPowerShell版本,只能輸出UTF-16LEBOM編碼。
在WindowsPowerShell5.1以前的版本,使用重新導向運算子(Redirectionoperators)預設會採用UTF-16LEBOM字集:
字集
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
Default(ANSI)
✅(Default)
❌
OEM(作業系統預設)
✅(Oem)
✅(oem)
ASCII(7-bit)字集
✅(Ascii)
✅(ascii)
UTF7
✅(UTF7)
✅(utf7)
UTF8(NoBOM)
❌
✅(utf8)
UTF8(NoBOM)
❌
✅(utf8NoBOM)(預設值)
UTF8BOM
✅(UTF8)
✅(utf8BOM)
UTF-16BEBOM
✅(BigEndianUnicode)
✅(bigendianunicode)
UTF-16LEBOM
✅(String)
❌
UTF-16LEBOM
✅(Unicode)(預設值)
✅(unicode)
UTF-16LEBOM
❌(Unknown)
❌
UTF-32BEBOM
❌(BigEndianUTF32)
✅(bigendianutf32)
UTF-32LEBOM
✅(UTF32)
✅(utf32)
Bytes
❌(Byte)
❌
關於Get-Content(讀取內容),Add-Content(添增內容),Set-Content(取代內容)的預設編碼
字集
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
Default(ANSI)
✅(Default)(預設值)
❌
OEM(作業系統預設)
✅(Oem)
✅(oem)
ASCII(7-bit)字集
✅(Ascii)
✅(ascii)
UTF7
✅(UTF7)
✅(utf7)
UTF8(NoBOM)
❌
✅(utf8)
UTF8(NoBOM)
❌
✅(utf8NoBOM)(預設值)
UTF8BOM
✅(UTF8)
✅(utf8BOM)
UTF-16BEBOM
✅(BigEndianUnicode)
✅(bigendianunicode)
UTF-16LEBOM
✅(String)
❌
UTF-16LEBOM
✅(Unicode)
✅(unicode)
UTF-16LEBOM
❌(Unknown)
❌
UTF-32BEBOM
❌(BigEndianUTF32)
✅(bigendianutf32)
UTF-32LEBOM
✅(UTF32)
✅(utf32)
Bytes
❌(Byte)
❌
不同Cmdlets之間,預設編碼不一樣,真的蠻讓人崩潰的。
但事實上,官網文件在針對Add-Content與Set-Content(取代內容)的說明也是有錯誤的。
當你在使用Add-ContentCmdlet的時候,他會判斷目標檔案的編碼,添加檔案時會以目標檔案的編碼為主,並不會使用Default(ANSI)編碼。
這裡所指的ANSI編碼,其實就是你控制台中地區設定的non-Unicode字集設定。
當你在使用Set-ContentCmdlet的時候,他並不會判斷目標檔案的編碼(但文件說會),所以這也是非常的雷!
當你在使用Get-ContentCmdlet的時候,預設使用Default編碼讀入。
事實上,PowerShellEngine在讀入PowerShellScript的時候,也是使用一樣的預設值。
關於Export-Csv的預設編碼
字集
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
Default(ANSI)
✅(Default)
❌
OEM(作業系統預設)
✅(Oem)
✅(oem)
ASCII(7-bit)字集
✅(Ascii)(預設值)
✅(ascii)
UTF7
✅(UTF7)
✅(utf7)
UTF8(NoBOM)
❌
✅(utf8)
UTF8(NoBOM)
❌
✅(utf8NoBOM)(預設值)
UTF8BOM
✅(UTF8)
✅(utf8BOM)
UTF-16BEBOM
✅(BigEndianUnicode)
✅(bigendianunicode)
UTF-16LEBOM
✅(String)
❌
UTF-16LEBOM
✅(Unicode)
✅(unicode)
UTF-16LEBOM
❌(Unknown)
❌
UTF-32BEBOM
❌(BigEndianUTF32)
✅(bigendianutf32)
UTF-32LEBOM
✅(UTF32)
✅(utf32)
Bytes
❌(Byte)
❌
上表WindowsPowerShell5.1以前的版本預設值,當你在設定-Append(添加)參數的時候,他就會改先判斷目標檔案的字集,以目標檔案的字集為主。
不過Out-File也有個-Append參數,這個參數不會判斷目標檔案的字集。
(為什麼設計的這麼不一致啊?)
關於Export-PSSession的預設編碼
字集
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
Default(ANSI)
✅(Default)
❌
OEM(作業系統預設)
✅(Oem)
✅(oem)
ASCII(7-bit)字集
✅(Ascii)
✅(ascii)
UTF7
✅(UTF7)
✅(utf7)
UTF8(NoBOM)
❌
✅(utf8)
UTF8(NoBOM)
❌
✅(utf8NoBOM)(預設值)
UTF8BOM
✅(UTF8)(預設值)
✅(utf8BOM)
UTF-16BEBOM
✅(BigEndianUnicode)
✅(bigendianunicode)
UTF-16LEBOM
✅(String)
❌
UTF-16LEBOM
✅(Unicode)
✅(unicode)
UTF-16LEBOM
❌(Unknown)
❌
UTF-32BEBOM
❌(BigEndianUTF32)
✅(bigendianutf32)
UTF-32LEBOM
✅(UTF32)
✅(utf32)
Bytes
❌(Byte)
❌
關於New-Item-TypeFile-Value的預設編碼
事實上New-ItemCmdlet並沒有-Encoding參數可用,但因為當你使用-TypeFile建立新檔案時,必須選用一個文字編碼,但他又不能指定-Encoding參數,預設值被設定成UTF8(NoBOM)編碼。
真的是非常的匪夷所思!
字集
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
Default(ANSI)
✅(Default)
❌
OEM(作業系統預設)
✅(Oem)
✅(oem)
ASCII(7-bit)字集
✅(Ascii)
✅(ascii)
UTF7
✅(UTF7)
✅(utf7)
UTF8(NoBOM)
❌
✅(utf8)
UTF8(NoBOM)
❌(預設值)
✅(utf8NoBOM)(預設值)
UTF8BOM
✅(UTF8)
✅(utf8BOM)
UTF-16BEBOM
✅(BigEndianUnicode)
✅(bigendianunicode)
UTF-16LEBOM
✅(String)
❌
UTF-16LEBOM
✅(Unicode)
✅(unicode)
UTF-16LEBOM
❌(Unknown)
❌
UTF-32BEBOM
❌(BigEndianUTF32)
✅(bigendianutf32)
UTF-32LEBOM
✅(UTF32)
✅(utf32)
Bytes
❌(Byte)
❌
關於Send-MailMessage的預設編碼
字集
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
Default(ANSI)
✅(Default)(預設值)
❌
OEM(作業系統預設)
✅(Oem)
✅(oem)
ASCII(7-bit)字集
✅(Ascii)
✅(ascii)
UTF7
✅(UTF7)
✅(utf7)
UTF8(NoBOM)
❌
✅(utf8)
UTF8(NoBOM)
❌
✅(utf8NoBOM)(預設值)
UTF8BOM
✅(UTF8)
✅(utf8BOM)
UTF-16BEBOM
✅(BigEndianUnicode)
✅(bigendianunicode)
UTF-16LEBOM
✅(String)
❌
UTF-16LEBOM
✅(Unicode)
✅(unicode)
UTF-16LEBOM
❌(Unknown)
❌
UTF-32BEBOM
❌(BigEndianUTF32)
✅(bigendianutf32)
UTF-32LEBOM
✅(UTF32)
✅(utf32)
Bytes
❌(Byte)
❌
關於Start-Transcript的預設編碼
字集
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
Default(ANSI)
✅(Default)
❌
OEM(作業系統預設)
✅(Oem)
✅(oem)
ASCII(7-bit)字集
✅(Ascii)
✅(ascii)
UTF7
✅(UTF7)
✅(utf7)
UTF8(NoBOM)
❌
✅(utf8)
UTF8(NoBOM)
❌
✅(utf8NoBOM)(預設值)
UTF8BOM
✅(UTF8)(預設值)
✅(utf8BOM)
UTF-16BEBOM
✅(BigEndianUnicode)
✅(bigendianunicode)
UTF-16LEBOM
✅(String)
❌
UTF-16LEBOM
✅(Unicode)
✅(unicode)
UTF-16LEBOM
❌(Unknown)
❌
UTF-32BEBOM
❌(BigEndianUTF32)
✅(bigendianutf32)
UTF-32LEBOM
✅(UTF32)
✅(utf32)
Bytes
❌(Byte)
❌
上表WindowsPowerShell5.1以前的版本預設值,當你在設定-Append(添加)參數的時候,他就會改先判斷目標檔案是否有BOM字元,如果有,就會以目標檔案的字集為主。
如果沒有,就會選用Ascii編碼。
變更PowerShell的預設編碼
你可以從上述的整理發現PowerShellCore6.0之後的版本,一律使用utf8NoBOM為預設編碼,一致性相當高!
但是WindowsPowerShell5.1以前的版本,預設編碼就非常混亂,很容易踩雷。
PowerShell有兩個預先定義好的變數,用來變更預設的編碼設定:
$PSDefaultParameterValues
如果你想改變>或>>重新導向的預設編碼,或是使用Out-FileCmdlet時想要改變預設編碼為UTF8BOM,可以這樣設定:
$PSDefaultParameterValues['Out-File:Encoding']='utf8'
如果想要改變所有Cmdlets的預設編碼,可以這樣寫:
$PSDefaultParameterValues['*:Encoding']='utf8'
你可以將設定加入到$PROFILE檔案中,這樣就可以統一所有Cmdlet的預設編碼。
$OutputEncoding
這個$OutputEncoding主要用來讓PowerShellCmdlet與外部程式(externalprograms)通訊的時候,指定的文字編碼,其預設值定義如下:
字集
WindowsPowerShell5.1以前的版本
PowerShellCore6.0之後的版本
Default(ANSI)
✅(Default)
❌
OEM(作業系統預設)
✅(Oem)
✅(oem)
ASCII(7-bit)字集
✅(Ascii)(預設值)
✅(ascii)
UTF7
✅(UTF7)
✅(utf7)
UTF8(NoBOM)
❌
✅(utf8)
UTF8(NoBOM)
❌
✅(utf8NoBOM)(預設值)
UTF8BOM
✅(UTF8)
✅(utf8BOM)
UTF-16BEBOM
✅(BigEndianUnicode)
✅(bigendianunicode)
UTF-16LEBOM
✅(String)
❌
UTF-16LEBOM
✅(Unicode)
✅(unicode)
UTF-16LEBOM
❌(Unknown)
❌
UTF-32BEBOM
❌(BigEndianUTF32)
✅(bigendianutf32)
UTF-32LEBOM
✅(UTF32)
✅(utf32)
Bytes
❌(Byte)
❌
WindowsPowerShell5.1以前的版本,這個$OutputEncoding預設變數定義的是Ascii編碼,這意味著所有從PowerShell導向到外面的資料,預設都會轉換成這個編碼:
❯$OutputEncoding
IsSingleByte:True
BodyName:us-ascii
EncodingName:US-ASCII
HeaderName:us-ascii
WebName:us-ascii
WindowsCodePage:1252
IsBrowserDisplay:False
IsBrowserSave:False
IsMailNewsDisplay:True
IsMailNewsSave:True
EncoderFallback:System.Text.EncoderReplacementFallback
DecoderFallback:System.Text.DecoderReplacementFallback
IsReadOnly:True
CodePage:20127
你可以透過[Console]::OutputEncoding取得目前Console可以使用的編碼,就會發現通常都與$OutputEncoding不一樣,這也意味著你從PowerShellCmdlet傳資料給傳統Windows外部程式的話,文字編碼通常都會出問題:
❯[Console]::OutputEncoding
EncodingName:ChineseTraditional(Big5)
WebName:big5
HeaderName:big5
BodyName:big5
Preamble:
WindowsCodePage:
IsBrowserDisplay:
IsBrowserSave:
IsMailNewsDisplay:
IsMailNewsSave:
IsSingleByte:False
EncoderFallback:System.Text.InternalEncoderBestFitFallback
DecoderFallback:System.Text.InternalDecoderBestFitFallback
IsReadOnly:False
CodePage:950
我舉的簡單的例子,在Windows有個findstr.exe工具,類似Linux下的grep工具,但是陽春很多。
假設我們在WindowsPowerShell這樣用,你會發現finstr什麼都搜尋不到,那是因為編碼不一致造成的:
Get-Content.\big5-example.txt|findstr測
但是如果我們把$OutputEncoding重新宣告成[Console]::OutputEncoding,PowerShellCmdlet所有輸出就會與Console的預設輸出編碼一致:
$OutputEncoding=[Console]::OutputEncoding
Get-Content.\big5-example.txt|findstr測
很可惜,PowerShell並沒有$InputEncoding可用,這意味著一個重大的資訊:你不能從其他應用程式傳入non-Unicode的字元給PowerShell使用!
WSL2
基本上Windows10內建所有的Terminal都是共用同一個超過30年沒有改進的核心,但是麻煩的地方在於WSL2開啟的時候,沒有chcp命令可用,而且預設Terminal採用UTF-8編碼,任何non-Unicode的編碼,通通無法正常顯示!
如下圖示,明明有4個bytes(兩個中文字),但卻一個字也吐不出來:
基本上,無解!你只能在WSL2處理Unicode編碼的文字!
WindowsTerminal+WSL2
使用Microsoft最新的WindowsTerminal來執行的話,有比較好一點,可以出現四個�字元,而且你依然無法調整預設字集!😅
基本上,一樣無解!你只能在WSL2處理Unicode編碼的文字!
PuTTY
使用PuTTY進行遠端連接,可以有效的解決各種編碼問題。
這是因為PuTTY內建一個叫做Charactersettranslation的功能,他可以讓你在建立連線之前,就先設定好遠端虛擬終端機想要使用預設字集,搭配著可以顯示該字集的字型,就可以正確顯示。
PuTTY預設採用UTF-8編碼,如果你的遠端Linux想以BIG5為預設字集,那麼你必須調整設定如下:
並選擇一個支援BIG5字集的字型:
連入之後,就可以正常顯示BIG5編碼的文字了
不過,當你想用WSL的時候,怎麼可能還特別安裝個OpenSSHServer然後再用PuTTY連進去,這雖然是在Linux下看到BIG5字集文字的「唯一」解決方案,但就是沒那麼漂亮!
我覺得要完美解決這個問題,大概只能依賴WindowsTerminal實現Charactersettranslation功能了,我特別到WindowsTerminal的GitHubRepo提出一個功能建議FeatureRequest:CharacterSettranslation#10870,希望日後有機會可以實現!
如何不透過PuTTY連線到Linux又能正確看到BIG5編碼的文字
我後來有研究出兩個方法,可以讓我在WSL下也能正確顯示BIG5的檔案內容:
使用cat搭配iconv轉換字集
反正文字只要能轉成UTF8就能正常顯示,所以這招可行!
catbig5-example.txt|iconv-fbig5-tutf8
不過,對於含有互動的命令介面下,這招就沒效了!Orz
使用pwsh搭配$PSDefaultParameterValues['*:Encoding']='big5'設定
這個方式則是利用PowerShellCore(pwsh)的特性,將Get-Content指定編碼為big5(CodePage950),然後利用PowerShellCore預設$OutputEncoding為UTF8的特性,將文字輸出成UTF8編碼,如此以來就可以順利顯示在畫面上了!😃
pwsh-Command'Get-Content-Encodingbig5./big5-example.txt'
pwsh-Command'Get-Content-Encoding950./big5-example.txt'
我可以寫成一個Alias專門來做這件事:
aliascatb5='pwsh-Command'"'"'Get-Content-Encodingbig5'"'"''
catb5./big5-example.txt
請注意:不要在PowerShellCoreonLinux使用cat命令,因為他會執行/usr/bin/cat命令,而非Get-ContentCmdlet喔!
總結
反正遇到編碼問題就是有著數不盡的地雷要踩,還好這幾年累積了無數踩雷經驗,今天終於將我所知道的編碼問題全部整理起來,心中頓時覺得踏實許多!😄
本文有點長,我特別節錄幾個重點知識:
Windows命令提示字元(CommandPrompt)可以用chcp切換預設編碼
chcp65001
PowerShell5.1+可以透過修改$PSDefaultParameterValues['*:Encoding']改變重新導向運算子的預設編碼
$PSDefaultParameterValues['*:Encoding']='utf8'
Get-Content./big5-example.txt
PowerShell5.1+預設所有>與>>導向都會委由Out-FileCmdlet處理
$PSDefaultParameterValues['Out-File:Encoding']='utf8bom'
Get-Content./big5-example.txt>abc.txt
PowerShell5.1+可以透過修改$OutputEncoding改變Pipe給外部程式的預設編碼
$OutputEncoding=[Console]::OutputEncoding
Get-Content./big5-example.txt|findstr/i測
PowerShellCore的編碼可以透過[System.Text.Encoding]::GetEncodings()取得完整清單,設定-Encoding的時候,可以指定CodePage的數字,也可以指定編碼名稱
[System.Text.Encoding]::GetEncodings()
Get-Content-Encoding950./big5-example.txt
Get-Content-Encoding'big5'./big5-example.txt
PuTTY內建一個叫做Charactersettranslation的功能,他可以讓你在建立連線之前,就先設定好遠端虛擬終端機想要使用預設字集,搭配著可以顯示該字集的字型,就可以正確顯示。
相關連結
[Console]::OutputEncodingunableswitchtocp950encodinginLinux#15865
$OutputEncodingtotherescue|PowerShellTeam
UnderstandingdefaultencodingandChangethesameinPowerShell
PowerShell輸出結果編碼問題
Howtoreadpipelinewithiso-8859-1encodingcharacters?#15871
HowtochangedefaultcodepageinWindowsTerminalusingWSL?-SuperUser
Putty中文顯示@廖董不懂的部落格::痞客邦::
相關文章
WindowsPhone7.5(Mango)開發學習資源整理
芒果終於要來了,昨天已經正式釋出WindowsPhoneSDK7.1RTM繁體中文版,而估計在幾週內應該所有WindowsPhone7的使用者就能夠自動更新到支援多國語系、完整的中...
WindowsContainer版本相容性與多重架構容器映像介紹
自從Windows核心版本v14393開始,也就是WindowsServer2016LTSC與Windows10年度更新版,正式開始支援Windows容器,這意謂著企業可以
徹底釐清Windows10與WindowsServer的版本編號
這些年一直對Windows10與WindowsServer的版本編號困擾著,經常會聽到什麼Windows10周年更新、Windows10創作者更新之類的名稱,完全摸不著頭緒,你
工商服務(廣告)
每月文章
2022
十月(5)
九月(17)
八月(10)
七月(11)
六月(4)
五月(10)
四月(5)
三月(9)
二月(9)
一月(15)
2021
十二月(12)
十一月(5)
十月(6)
九月(13)
八月(16)
七月(13)
六月(13)
五月(7)
三月(1)
二月(1)
2020
十二月(3)
十一月(1)
十月(3)
九月(7)
八月(7)
七月(9)
六月(2)
五月(5)
三月(4)
二月(5)
一月(4)
2019
十二月(7)
十一月(2)
十月(5)
九月(1)
六月(3)
四月(4)
三月(3)
二月(7)
一月(12)
2018
十二月(3)
十一月(1)
十月(4)
九月(12)
八月(4)
六月(2)
五月(3)
四月(6)
二月(1)
一月(2)
2017
十二月(2)
十月(3)
九月(4)
七月(1)
六月(1)
五月(1)
四月(1)
二月(3)
一月(4)
2016
十二月(4)
十一月(1)
十月(1)
九月(4)
八月(3)
七月(2)
五月(1)
四月(1)
三月(3)
二月(3)
一月(2)
2015
十二月(6)
十一月(4)
十月(3)
九月(5)
八月(1)
七月(4)
六月(2)
五月(3)
四月(1)
三月(1)
二月(3)
一月(2)
2014
十二月(3)
十一月(2)
十月(3)
九月(3)
八月(1)
七月(4)
六月(2)
五月(4)
四月(5)
三月(4)
二月(1)
一月(7)
2013
十二月(1)
十一月(8)
十月(1)
九月(2)
八月(4)
七月(5)
六月(8)
五月(9)
四月(8)
三月(10)
二月(9)
一月(10)
2012
十二月(4)
十一月(6)
十月(6)
九月(4)
八月(5)
七月(10)
六月(5)
五月(6)
四月(10)
三月(12)
二月(1)
一月(6)
2011
十二月(3)
十一月(7)
十月(8)
九月(14)
八月(15)
七月(10)
六月(10)
五月(11)
四月(11)
三月(13)
二月(14)
一月(13)
2010
十二月(13)
十一月(10)
十月(16)
九月(17)
八月(12)
七月(22)
六月(15)
五月(11)
四月(14)
三月(17)
二月(17)
一月(26)
2009
十二月(16)
十一月(18)
十月(18)
九月(23)
八月(20)
七月(26)
六月(24)
五月(21)
四月(26)
三月(30)
二月(27)
一月(26)
2008
十二月(30)
十一月(31)
十月(31)
九月(29)
八月(31)
七月(31)
六月(30)
五月(30)
四月(31)
三月(31)
二月(29)
一月(33)
2007
十二月(31)
十一月(37)
十月(13)
文章分類
.Net
(223)
.NETCore
(57)
Accessibility
(3)
Angular
(25)
AngularJS
(11)
ASP.NET
(223)
ASP.NET5
(3)
ASP.NETBlazor
(1)
ASP.NETCore
(37)
ASP.NETIdentity
(2)
ASP.NETMVC
(105)
ASP.NETWebAPI
(13)
AzureDevOps
(33)
C#
(127)
CloudComputing
(4)
CSS
(29)
DevOps
(22)
Docker
(28)
EntityFramework
(23)
Git
(31)
Golang
(2)
HTML5
(8)
IIS
(103)
Java
(26)
JavaScript
(108)
Jenkins
(7)
Kubernetes
(15)
LINQ
(36)
Linux
(114)
MicroK8s
(7)
MicrosoftAzure
(41)
MySQL
(15)
Office
(49)
Office365
(28)
Oracle
(10)
PHP
(25)
Scrum
(1)
Security
(66)
SQLServer
(127)
Subversion
(35)
SystemCenter
(2)
TFS
(6)
TFS2010
(10)
Tips
(190)
UnitTesting
(10)
Usability
(1)
VBA
(5)
VisualBasic
(5)
VisualStudio
(122)
VisualStudio11
(2)
VisualStudio2012
(10)
VisualStudio2013
(4)
VS2010Tips
(23)
Web
(172)
WebMatrix
(8)
Windows
(45)
Windows8
(14)
WindowsAzure
(18)
WindowsPhone7
(14)
介紹好用工具
(228)
心得分享
(88)
多奇快訊
(9)
系統管理
(368)
前端工程研究
(20)
專案管理
(8)
團隊合作
(9)
網路管理
(22)
延伸文章資訊
- 1關於字元編碼- PowerShell - Microsoft Learn
如果您需要在腳本中使用非Ascii 字元,請使用BOM 將它們儲存為UTF-8。 如果沒有BOM,Windows PowerShell將腳本誤譯為在舊版「ANSI」 字碼頁中編碼。
- 2PowerShell 中文亂碼問題(Big5 / Big-5 / UTF8 / UTF ... - Dino9021
https://docs.microsoft.com/zh-tw/powershell/module/microsoft.powershell.core/ ... $PSDefaultParam...
- 3分享幾個在Windows 與Linux 常見的編碼問題與解決方案
看到上述這麼多支援的編碼不同,而跙Windows PowerShell 5.1 以前的版本竟然沒辦法指定UTF8 (No BOM) 的輸出,實在母湯!👎.
- 4Command Prompt / Windows Powershell 預設使用UTF-8 編碼 ...
此文主要協助各位調整Command Prompt / Windows Powershell 預設使用UTF-8 編碼,有興趣就往下看吧! 本篇目錄[隱藏]. 前言; 臨時修改; 永久修改. Co...
- 5解決Git 中文亂碼- Windows Powershell - HackMD
預設使用UTF-8 編碼. 根據Stackoverflow 上所提到的,先來確認 [console]::OutputEncoding 、 ...