需求
衆所周知的問題,現在視頻網站發佈視頻的方式方法已經有了很大的改變。比如mp4文件改名爲mp41,類似下面這樣
PS E:\BaiduNetdiskDownload> ls *.mp41 -Recurse
目?錄?: E:\BaiduNetdiskDownload
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019/8/11 20:42 1322066936 [SUBPIG][Eien no Nispa SP].mp41
然而實際按照
[SUBPIG][Eien no Nispa SP].mp41
這個文件名,用rename的方式去修改,卻被提示失敗。
PS E:\BaiduNetdiskDownload> Rename-Computer "[SUBPIG][Eien no Nispa SP].mp41" "[SUBPIG][Eien no Nispa SP].mp4"
Rename-Computer : 找不到接受實際參數“[SUBPIG][Eien no Nispa SP].mp4”的位置形式參數。
所在位置 行:1 字符: 1
+ Rename-Computer "[SUBPIG][Eien no Nispa SP].mp41" "[SUBPIG][Eien no N ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Rename-Computer],ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.RenameComputerCommand
自動補齊
這是爲什麼呢?其實原因很簡單,因爲PowerShell中,對於[]符號有特殊的定義,所以不能這麼寫。
我們試試在命令行下直接運行它,系統會自動補齊什麼樣的字符轉義
PS E:\BaiduNetdiskDownload> & '.\[SUBPIG][Eien no Nispa SP].mp41'
可以看到字符串前面有& 然後跟一個空格,字符串被' (單引號)包裹,這種方法可以用來運行一些包含了特殊字符的命令行工具,或者可執行程序,但是,在傳遞參數的時候還是用不了的。
我們試試,在某一個參數中,指定路徑或者文件名,看系統自動補齊會變成什麼樣子
PS E:\BaiduNetdiskDownload> Rename-Item -Path '.\`[SUBPIG`]`[Eien no Nispa SP`].mp41'
大概這就是正確方式了吧,專門寫了個函數
function EscapeWord ($param1) {
if ($param1 -match "[[]" -or $param1 -match "[]]") {
$param1.replace('[', '`[').replace(']', '`]')
}
}
EscapeWord "E:\BaiduNetdiskDownload\[SUBPIG][FAKE AFFAIR EP05].mp41"
E:\BaiduNetdiskDownload\`[SUBPIG`]`[FAKE AFFAIR EP05`].mp41
先單獨一條數據執行下
PS E:\BaiduNetdiskDownload> Rename-Item -Path '.\`[SUBPIG`]`[Eien no Nispa SP`].mp41' -NewName '.\`[SUBPIG`]`[Eien no Nispa SP`].mp4'
Rename-Item : 指定路徑 E:\BaiduNetdiskDownload\`[SUBPIG`]`[Eien no Nispa SP`].mp41 下的對象不存在。
實際來看,還是失敗了。
變通解決
實在是挺無語的,既然[]在PowerShell下被重新定義了,那CMD下總是好的吧。用CMD來混合一下。這次的做法是切割名稱字符串,把最後一個字符串切掉,然後替換名稱。依然可以達到需求,並且修改記錄還會追加保存在一個文件中。
(Get-ChildItem *.mp41 -Recurse) | ForEach-Object { $fullname = $_.fullname
$fullname
$NewName = $_.name
$NewName = ($NewName[0..($NewName.Length - 2)] -join "")
$NewName
$info = "rename `"$fullname`" `"$NewName`""
cmd /c $info
$info | Out-File c:\333.txt -Append -Force -Encoding utf8
}
高亮測試
最終方案
問題是解決了,但是實現方法太擰巴。如果有原生方法,上面的操作還是不會考慮的。
我通過搜關鍵字
rename file PowerShell match []
在東家找到了下面一個最終極的方案。
https://answers.microsoft.com/en-us/windows/forum/windows_10-files/how-to-rename-image-files-in-a-folder-all-to-jpg/2a7e2873-e04b-472b-b239-afad2f2020fc
果然解決不了的時候直接上.net都是一件利器。
Get-ChildItem *.mp41 -Recurse | Rename-Item -newname { [io.path]::ChangeExtension($_.name, "mp4") }
在 https://stackoverflow.com/questions/5574648/use-regex-powershell-to-rename-files 也發現一個很有意思的替換方法,不過一樣的,受限於[],不太適合我的場景。
Get-ChildItem *.mp41 | ForEach-Object{ Rename-Item $_ $(($_.name -replace '^filename_+','') -replace '_+',' ') }
剩下的問題
其實到這裏,還有一個坑,如果有一天,需要對包含[]的文件,替換文件名,應該如何做呢?