Poy Chang's Blog

使用 PowerShell 建立修改檔案內容的指令

今天遇到一個奇妙的情況,同事上傳的檔案內容出現一個奇妙的字元亂碼,上傳的程式修正了,但已經上傳的檔案內容需要移除那個奇妙的字元,因此想用 PowerShell 寫一隻指令來處理看看,順便也補充一下 PowerShell 知識。

前情提要

該檔案使用 UCS-2 LE BOM 編碼,其實這相當於 UTF-16 編碼(兩者的關係參考這裡),再加上使用 little-endian 的排序方式。

之所以會出現奇妙的字元,是因為每此 Append 內容進檔案的時候,把編碼標頭也 Append 上去,這就造成了亂碼。

亂碼 \ufeff

這個亂碼其實是個 \ufeff 字元,只是它顯示不出來。

處理幾件小事情

要調整的檔案數量不在少數,要修改成千上百個檔案可不是開玩笑的。

第一步當然就是取得所有檔案的路徑,在 PowerShell 的環境中取得指定資料夾底下的所有檔案路徑算簡單的,Get-ChildItem -Path "YOUR_FOLDER_PATH" -File 一行搞定。

第二步就是逐一打開前一步取得的檔案內容,然後替換掉指定的字元,這裡稍微不好處理,PowerShell 沒有提供直接取代檔案內容的 Cmdlet,為了讓指令盡可能單純,我選擇這樣的解法:

1
(Get-Content -path "FILE_PATH" -Raw) -replace "SEARCH_TARGET", "REPLACE_VALUE"

先將該檔案內容用 Get-Content 取出,然後這個值當然就是個字串,這時再使用字串的 Replace 功能,這樣指令就相當簡潔了。

第三步就是把還存在記憶體中的修改後字串,存進原本的檔案中,這只需要用到 Set-Content 這支 Cmdlet 就搞定了!不過有一點要注意的是,預設會使用 UTF-8 without BOM 的編碼,前情提要有講到編碼要用 UCS-2 LE BOM,因此要再指定 Set-Content-Encoding 參數為 unicode

把二、三部的指令用 | 管線符號串起來,就差不多完成囉!

1
(Get-Content -path "FILE_PATH" -Raw) -replace "SEARCH_TARGET", "REPLACE_VALUE" | Set-Content -Path "FILE_PATH" -Encoding unicode

完整的 Function

寫成 PowerShell Function 就是下面這樣囉,開放三個參數以便後續使用,其中第三個 Replace 的參數要稍微注意一下,因為有可能是要替換成空字串,因此這個參數需要掛上 [AllowEmptyString()] 讓它可以接受空字串,不然執行的時候可是會報錯的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function Update-FileContent {
Param(
[Parameter(
Mandatory = $true,
Position = 0,
HelpMessage = "Folder path"
)]
[string]$Path,
[Parameter(
Mandatory = $true,
Position = 1,
HelpMessage = "Search content"
)]
[string]$Search,
[Parameter(
Mandatory = $true,
Position = 2,
HelpMessage = "Replace to"
)]
[AllowEmptyString()]
[string]$Value
)

$files = Get-ChildItem -Path $Path -File
foreach ($file in $files) {
Write-Verbose -Message "Replace From: $file.FullName"
((Get-Content -path $file.FullName -Raw) -replace $Search, $Value) | Set-Content -Path $file.FullName -Encoding unicode
}
}

在 Function 裡面用到了 Write-Verbose 這個 Cmdlet,這是當執行此指令時,有加上 -Verbose 參數才會輸出該段訊息。


參考資料: