Logo

dev-resources.site

for different kinds of informations.

PowerShell 的文字編碼

Published at
1/14/2025
Categories
powershell
Author
codemee
Categories
1 categories in total
powershell
open
Author
7 person written this
codemee
open
PowerShell 的文字編碼

輸出到檔案的編碼

PowerShell 的 > 與 >> 其實就是 Out-File 這個 cmdlet, 它在輸出文字到檔案時可以使用 -encoding 選項指定檔案的文字編碼, 你也可以透過 $PSDefaultParameterValues[Out-File:Encoding] 設定預設採用的 -encoding 選項值。

若沒有設定, PowerShell 7 預設是 UTF8、PowerShell 5 預設是具有 BOM(Byte order mark)UTF16LE。例如:

  • 在 PowerShell 5 中:

    > echo 測試 > out_ps5.txt
    > ls .\out_ps5.txt
    
      目錄: D:\code\test_ampy
    
    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    -a----       2021/7/17  下午 01:20             10 out_ps5.txt
    

    檔案內容就是 2 個位元組的 BOM、各 2 個位元組的 2 個中文字、以及各 2 個位元組表示結尾的 \x0D\x00 與 \x0A\x00:

    FF FE 2C 6E 66 8A 0D 00 0A 00
    

    其中開頭的 \xFF\xFE 表示這是 little endian 位元組順序UTF16 檔案, 因為是 little endian 位元組順序, 所以 \x2C\x6E 就是將低位元組排到前面後的 Unicode \x6E\x2C, 也就是『』、\x66\x8A 是 Unicode 編碼 \x8A\x66 的『』。由於是 UTF16, 所以換行字元也都各是 2 個位元組。

    如果在 PowerShell 5 中設定為使用 utf8 , 輸出檔案就會採用具有 BOM 的 UTF8 編碼

    > $PSDefaultParameterValues['Out-File:Encoding']='utf8'
    > echo 測試 > out_ps5.txt
    > ls .\out_ps5.txt
    
      目錄: D:\code\test_ampy
    
    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    -a----       2021/7/17  下午 01:32             11 out_ps5.txt
    

    實際內容如下:

    EF BB BF E6 B8 AC E8 A9 A6 0D 0A
    

    開頭的 \xEF\xBB\xBF 就是 BOM, 表示此檔案是以 UTF-8 編碼。接著的內容是各 3 個位元組的 2 個中文字, 加上換行的 \x0D\x0A 共 8 個位元組, 其中 \xE6\xB8\xAC 是『』、\xE8\xA9\xA6 是『』。

    PowerShell 5 中 -encoding 允許的編碼有以下這幾種, 預設是 Unicode:

    參數值 編碼
    ASCII 7 位元的 ASCII 編碼
    BigEndianUnicode big endian 位元組順序的 UTF-16
    Default 系統設定的編碼頁
    OEM 系統 OEM 設定的編碼頁
    String 同 Unicode
    Unicode little endian 位元組順序的 UTF-16
    Unknown 同 Unicode
    UTF7 UTF-7
    UTF8 UTF-8
    UTF32 little endian 位元組順序的 UTF-32
  • 在 PowerShell 7 中:

    ❯ echo 測試 > out_ps7.txt
    ❯ ls out_ps7.txt
    
      Directory: D:\code\test_ampy
    
    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    -a---         2021/7/17 下午 01:17              8 out_ps7.txt
    

    檔案內容沒有 BOM, 並且以 UTF-8 編碼, 為各 3 個位元組的 2 個中文字, 加上換行的 \x0D\x0A 共 8 個位元組:

    E6 B8 AC E8 A9 A6 0D 0A
    

    其中 \xE6\xB8\xAC 是『』、\xE8\xA9\xA6 是『』。

    在 PowerShell 7 中 -encoding 可接受的參數值如下, 預設為 utf8NoBOM:

    參數值 編碼
    ASCII 7 位元的 ASCII 編碼
    BigEndianUnicode big endian 位元組順序的 UTF-16
    BigEndianUTF32 big endian 位元組順序的 UTF-32
    OEM MS-DOS 與終端機的字元編碼
    Unicode little endian 位元組順序的 UTF-16
    UTF7 UTF-7(已不建議使用)
    UTF8 UTF-8(同 UTF8NoBOM)
    UTF8BOM 具有 BOM 的 UTF-8
    UTF8NoBOM 沒有 BOM 的 UTF-8
    UTF32 little endian 位元組順序的 UTF-32
    編碼頁或其名稱 例如 950 是 big5
    ❯ $PSDefaultParameterValues['Out-File:Encoding']='big5'
    ❯ echo 測試 > out_ps7.txt
    ❯ ls out_ps7.txt
    
      Directory: D:\code\test_ampy
    
    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    -a---         2021/7/17 下午 01:55              6 out_ps7.txt
    

    檔案長度就變成 2 個各佔 2 個位元組的中文字以及換行符號的 2 個位元組, 共 6 個位元組了。

請特別留意:PowerShell 7.4 之後外部程式輸出轉向到檔案已經不是透過 Out-File 轉碼, 而是保留原始輸出內容不動直接存檔, 所以如果外部程式輸出內容為 big5 編碼的文字, 轉向存檔內容就一樣是 big5 編碼。

從檔案讀取文字時的編碼

從檔案讀取文字的 Get-Content 和輸出文字到檔案的 Out-File 都有 -encoding 選項可以設定文字編碼。例如以下將『測試』兩字分別以不同編碼方式存檔:

❯ echo 測試 | Out-File out_utf8.txt
❯ echo 測試 | Out-File -Encoding big5 out_big5.txt
Enter fullscreen mode Exit fullscreen mode

若不指定 -encoding 選項, 預設就是 UTF-8 編碼, 因此以下兩次使用 Get-Content 讀取剛剛存好的檔案, 在讀取 BIG5 編碼的檔案時就會解譯錯誤:

❯ Get-Content .\out_utf8.txt
測試
❯ Get-Content .\out_big5.txt
����
Enter fullscreen mode Exit fullscreen mode

如果指定使用 BIG5 編碼, 就會正確:

❯ Get-Content -Encoding big5 .\out_big5.txt
測試
Enter fullscreen mode Exit fullscreen mode

你也可以使用 $PSDefaultParameterValues['Get-Content:encoding'] 來設定 Get-Content 預設的 -encoding 選項值:

❯ $PSDefaultParameterValues['Get-Content:encoding']='big5'
❯ Get-Content .\out_big5.txt
測試
Enter fullscreen mode Exit fullscreen mode

如果是具有 BOM 的檔案, 那麼即使不指定編碼, 甚至指定錯誤的編碼, Get-Content 都還是可以從 BOM 得到正確的編碼, 解讀檔案中的文字。

外部程式輸出到終端機時的編碼

PowerShell 本質是一個 .net 的 console 程式, 外部程式如果要顯示文字到畫面上, 就是由 [console]::OutputEncoding 來決定要如何解譯外部程式輸出的文字。例如以下這個 print.c 程式, 同時會輸出『測試』兩字以 UTF-8 及 Big5 編碼的位元組序列:

#include<stdio.h>
#include <unistd.h>
#include <string.h>

int main(){
  char strUTF8[] = "UTF8:\xE6\xB8\xAC\xE8\xA9\xA6\x0A";
  char strBIG5[] = "BIG5:\xB4\xFA\xB8\xD5\x0A";
  write(1, strUTF8, strlen(strUTF8));
  write(1, strBIG5, strlen(strBIG5));
}
Enter fullscreen mode Exit fullscreen mode

在 PowerShell 預設的情況下, [console]::OutputEncoding 是 big5:

❯ [console]::OutputEncoding

EncodingName      : Chinese Traditional (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
Enter fullscreen mode Exit fullscreen mode

所以執行 print.c 程式只有 BIG5 編碼的位元組序列才能正確顯示『測試』:

❯ .\print
UTF8:皜祈岫
BIG5:測試
Enter fullscreen mode Exit fullscreen mode

UTF-8 位元組序列所顯示的『皜祈岫』是把 \xE6\xB8\xAC\xE8\xA9\xA6\x0A 當成 BIG5 解譯, 所以把 \xE6\xB8 當一個字, 變成『』;\xAC\xE8 當一個字, 變成『』;\xA9\xA6 也當一個字, 變成『』了。

如果修改設定, 改採 UTF-8 編碼:

❯ [console]::OutputEncoding=[text.encoding]::UTF8
Enter fullscreen mode Exit fullscreen mode

就會變成以 UTF-8 編碼的位元組序列可以正常顯示『測試』, 而 BIG5 編碼的位元組序列因為不符合 UTF-8 編碼規則, 顯示成 3 個『�』:

❯ .\print
UTF8:測試
BIG5:���
Enter fullscreen mode Exit fullscreen mode

只要設定回原本的編碼方式, 就又恢復原樣了。要以編碼頁取得特定編碼, 可以使用[text.encoding]::GetEncoding()

❯ [console]::OutputEncoding=[text.encoding]::GetEncoding(950)
❯ [console]::OutputEncoding

EncodingName      : Chinese Traditional (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


❯ .\print
UTF8:皜祈岫
BIG5:測試
Enter fullscreen mode Exit fullscreen mode

從終端機輸入文字到外部程式時的文字編碼

要從終端機輸入資料到外部程式時,是由 [Console]::InputEncoding 來決定使用哪一種文字編碼,預設是 utf-8:

❯ [Console]::InputEncoding

Preamble          :
BodyName          : utf-8
EncodingName      : Unicode (UTF-8)
HeaderName        : utf-8
WebName           : utf-8
WindowsCodePage   : 1200
IsBrowserDisplay  : True
IsBrowserSave     : True
IsMailNewsDisplay : True
IsMailNewsSave    : True
IsSingleByte      : False
EncoderFallback   : System.Text.EncoderReplacementFallback
DecoderFallback   : System.Text.DecoderReplacementFallback
IsReadOnly        : True
CodePage          : 65001
Enter fullscreen mode Exit fullscreen mode

舉例來說, 我撰寫了一個可以將標準輸入的資料以 16 進位顯示的 getch.c 程式:

#include <stdio.h>
#include <unistd.h>

int main( ) {
  unsigned char c;
  int count;

  while((count=read(0, &c, 1))>0) {
    printf("\\x%02X", c);
    if(c==0x0a) {
      return 0;
    }
  }
  return 0;
}
Enter fullscreen mode Exit fullscreen mode

直接執行並且輸入 "測試":

❯ ./getch
測試
\xE6\xB8\xAC\xE8\xA9\xA6\x0A
Enter fullscreen mode Exit fullscreen mode

可以看到取得的是 utf-8 編碼的結果。如果更改編碼為 big5,我們先確認目前終端機輸出的編碼:

❯ [Console]::OutputEncoding

EncodingName      : Chinese Traditional (Big5)
WebName           : big5
HeaderName        : big5
BodyName          : big5
Preamble          :
WindowsCodePage   :
IsBrowserDisplay  :
IsBrowserSave     :
IsMailNewsDisplay :
IsMailNewsSave    :
IsSingleByte      : False
EncoderFallback   : System.Text.InternalEncoderBestFitFallba
                    ck
DecoderFallback   : System.Text.InternalDecoderBestFitFallba
                    ck
IsReadOnly        : False
CodePage          : 950
Enter fullscreen mode Exit fullscreen mode

現在把終端機輸入的編碼改成和輸出一樣:

❯ [Console]::InputEncoding = [console]::OutputEncoding
# ./getch
測試
\xB4\xFA\xB8\xD5\x0A
Enter fullscreen mode Exit fullscreen mode

你可以看到現在收到的是 big5 編碼的結果了。

透過資料通道輸出給外部程式時的編碼

$OutputEncoding 變數是 PowerShell 透過資料通道輸出給外部程式時的文字編碼, 但不會影響 >、>>、Out-File 採用的編碼,預設也是 utf-8。

我們一樣可以透過剛剛的 getch 程式來觀察透過 PowerShell 的資料通道實際送來的內容:

❯ echo 測試 | .\getch
\xE6\xB8\xAC\xE8\xA9\xA6\x0A
Enter fullscreen mode Exit fullscreen mode

可以看到 getch 收到的是 UTF8 編碼的文字。如果我們將 $OutputEncoding 修改成其他編碼, 例如這裡我們把 $OutputEncoding 設定成和終端機輸出的編碼一樣,再進行同樣的測試:

❯ $OutputEncoding = [Console]::OutputEncoding
❯ echo '測試' | ./getch
\xB4\xFA\xB8\xD5\x0A
Enter fullscreen mode Exit fullscreen mode

就可以看到 getch 收到的變成是 big5 編碼的文字了。

powershell Article's
30 articles in total
Favicon
Windows 上 VSCode 的 C/C++ 延伸模組處理編碼的問題
Favicon
PowerShell 的文字編碼
Favicon
笔记3
Favicon
TryHackMe | Windows PowerShell | RSCyberTech
Favicon
Configuring Hyper-V Global Default Directories
Favicon
How I Set Up an Awesome PowerShell Environment for Script Development
Favicon
Azure Function App (Flex Consumption) PowerShell Modules solution
Favicon
File Comparison Made Easy: Detecting New and Changed Files with PowerShell
Favicon
10 Best Practices of PowerShell Code Signing for Signing Your Script
Favicon
PowerShell Script Collection: Automation and Solutions for Everyday Tasks
Favicon
Video: List All Available Windows Features on Windows 11 using CMD & PowerShell
Favicon
Set up Azure Network Security Perimeter with PowerShell
Favicon
Automating Azure Project Setup with PowerShell and GitHub Actions
Favicon
Azure Function App (Flex Consumption) in private VNET via IaC
Favicon
Using PowerShell to Create Service Principals for RBAC
Favicon
Two ways to use Pester to Mock objects with strongly typed parameters
Favicon
PowerShell Automation: Execute Batch GitHub CLI Commands
Favicon
❓ Do you allow wrong input to enter your function?
Favicon
Introducing PowerShell Utility Scripts
Favicon
Cisco DHCP Pool conversion to Windows Server DHCP
Favicon
PowerShell | Script output garbled Chinese characters
Favicon
Rename Multiple Files in Sequence with Just One Click Using PowerShell in Windows! 🚀
Favicon
Redirect Out-File to TestDrive: in your PowerShell Pester test scripts with this one weird trick
Favicon
Using PowerShell for day to day stuff
Favicon
Automating SharePoint Embedded: Using PowerShell to Call Graph API Endpoints
Favicon
Install Ubuntu on WSL 2
Favicon
How to Install WSL from PowerShell on Windows 10 and 11
Favicon
How to Run PowerShell Script in Jenkins Pipeline
Favicon
Identify Which Files are Large.
Favicon
Quick guide to setting up an shortcut/alias in windows

Featured ones: