4

PowerShell 傳遞含雙引號與空白的複雜參數給外部 EXE

 3 years ago
source link: https://blog.darkthread.net/blog/ps-pass-args-w-space/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
PowerShell 傳遞含雙引號與空白的複雜參數給外部 EXE-黑暗執行緒

前幾天提到我要下載 Podcast 音檔存入 MP3 運動耳機跑步時聽。平常用手機聽中文 Podcast 我會加快 20% ~ 50% 省點時間,但 MP3 耳機不能調播放速度,所以我想跑批次作業將 MP3 加速後另存新檔。要達成此任務,強大的開源自由軟體多媒體轉檔工具 - FFmpeg 是首選。

https://github.com/BtbN/FFmpeg-Builds 找到編譯好的 Windows 版 (註:下載版本很多,N-xxxxxx 是 Nightly-Build 即時新版,-n4.4 是較穩定的發行版 參考,選 win64-gpl 版) 取得神奇的 ffmpeg.exe,執行 ffmpeg -i input.mp3 -filter:a "atempo=1.5" -vn output.mp3 可將 input.mp3 加速 50% 另存成 output.mp3。參考

我打算寫一小段 PowerShell 列舉原始 MP3,加速另存新檔再取代原檔。本以為是個簡單任務,想說寫一下放著跑去洗澡,沒想到一不小心踩坑,搞到凌晨澡都還沒洗。

PowerShell 要呼叫外部 EXE 程式並動態決定參數,使用呼叫運算子 & 是最簡單做法:

不過,這次的檔名參數有空白還需要雙引號包夾,我怎麼都無法用變數組裝出可執行的 ffmpeg.exe -i ".\EP121 我不是登徒子啦.mp3" -filter:a "atempo=1.5" -vn ".\EP121 我不是登徒子啦.x15.mp3"

# 沒用變數時,寫死檔名沒問題
& '.\ffmpeg.exe' -i ".\EP121 我不是登徒子啦.mp3" -filter:a "atempo=1.5" -vn ".\EP121 我不是登徒子啦.x15.mp3"

$fn = "EP121 我不是登徒子啦"

# 轉成內容一模一樣的字串變數卻不行
$argStr = "-i `".\$fn`" -filter:a `"atempo=1.5`" -vn `".\$fn.x15.mp3`""
& '.\ffmpeg.exe' $argStr
# 錯誤:Unrecognized option 'i .\EP121'.
# Error splitting the argument list: Option not found

# 拆成三個參數不行,雙引號似乎沒作用,EP121 空格後方被當成下一個參數
# 註:雙引號包含內容要 Escape 雙引號,寫 `" 或 "" 都行
$i = "-i `".\$fn.mp3`""
$vn = "-vn `".\$fn.x15.mp3`""
$filter = '-filter:a "atempo=1.5"'
& '.\ffmpeg.exe' $i $filter $vn
# 錯誤:Unrecognized option 'i .\EP121'.
# Error splitting the argument list: Option not found

# 寫成 \",ffmpeg 會看到 ",含空白的路徑被視為一個字串,但仍無法執行
$i = "-i \`".\$fn.mp3`""
$vn = "-vn `".\$fn.x15.mp3`""
$filter = '-filter:a "atempo=1.5"'
& '.\ffmpeg.exe' $i $filter $vn
# 錯誤:Unrecognized option 'i ".\EP121 我不是登徒子啦.mp3"'.
# Error splitting the argument list: Option not found

搞了大半天沒結果,上網查資料,發現這是一個很容易踩到的坑。PowerShell 解析參數時,對於單引號、雙引號一個或兩個、前面有沒有加 \,以及中間是否包含空白的解析規則遠比想像複雜,例如以下這張表:

參考來源

【延伸閱讀】

這個解析規則複雜度之高,高到開發社群甚至寫了個小工具 EchoArgs.exe 協助除錯,它被包含在 Pscx (PowerShell Community Extension) 模組,理論上可以用 Install-Module 安裝,但 Pscx 有點年久失修,安裝時會遇到 此系統上已有下列命令: 'gcb,Expand-Archive,Forma t-Hex,Get-Hash,help,Invoke-NullCoalescing,prompt,Dismount-VHD,Get-Clipboard,Get-Hel p,Mount-VHD,Set-Clipboard'。 錯誤,我選擇從 Manual Download 下載 .nupkg 檔解壓縮取檔。

將 ffmpeg.exe 換成 EchoArgs.exe,很快就知道我們傳入的參數是如何被曲解了::D

用對工具,很快找出正確的寫法 & '.\ffmpeg.exe' -i ".\$fn.mp3" -filter:a "atempo=1.5" -vn ".\$fn.x15.mp3",答案出奇簡單,"$fn.mp3" 本身已算一個獨立參數,不需特別再加雙引號。

掌握這個技巧,未來在 PowerShell 傳遞內含空白參數給外部 EXE 時,就不會像無頭蒼蠅到處亂轉了。


Recommend

  • 13

    PowerSehll 小技巧 - 開關參數與腳本使用說明-黑暗執行緒分享最近的學會的 PowerShell 技巧兩則。 第一個是如何為 ps1 腳本加上啟用特定功能的開關。我以前比較笨,都是另設字串參數預設為 N,要啟用就傳入 Y,例如:-IncludeSubFolder Y。但 PowerShell...

  • 10

    PowerShell - 將多參數以陣列變數傳入函式-黑暗執行緒分享最近學到的 PowerShell 小技巧。 假設我有個接受多個參數的函式,有三種參數寫法。第一種是寫成 FuncName Arg1 Arg2 Arg3... 依序列出,中間以空白間隔(注意:不要加 ( ) 及 ,,參考:

  • 4

    前言 如果你有使用過 Tensorflow(以下簡稱 TF),特別是很前期的 API,你有很高機率也經歷過一段痛苦的學習經驗,有這種體驗的你並不孤單,一方面是 TF low-level API 的使用邏輯不是很符合直覺(API 文件也寫得不是很清楚),另一方...

  • 10

    PowerShell ConvertTo-Json 複雜巢狀結構注意事項-黑暗執行緒 ConvertTo-Json/ConvertFrom-Json 是少數我用不順手的 PowerShell 指令,過去就踩過幾次雷(ConvertFrom-JSON 解析大型...

  • 4

    C# 小技巧 - 使用匿名型別傳遞多參數 2021-11-02 09:15 PM

  • 24

    ASP.NET Core JSON 中文編碼問題與序列化參數設定-黑暗執行緒 轉進 ASP.NET Core 世界,依循過去寫 MVC 經驗,加上參考網路技術文章(當然,還有流著奶與蜜的 Stackoverflow) 大致還算都順利,但不時發現新的眉角。 今天遇到的問題是

  • 7

    以 EIP-3668 進行鏈下 / 跨鏈資料傳遞本文主要介紹 EIP-3668 這個作為智能合約將鏈下資料無需信任地取回的一種標準。

  • 4

    用情趣用品在西洋棋比賽裡面傳遞摩斯電碼作弊 標題資訊量有點大... 先講一下最近西洋棋界的新聞,九月的時候

  • 3

    【笨問題】CLI 參數為什麼有時要加 "--"? POSIX 參數慣例的冷知識-黑暗執行緒 講到指令工具參數,Windows 老人的印象有可能還停留 /?、/S 之類的斜線表示法,例如: DIR /S D:\TEMP XCOPY D:\...

  • 6

    .NET 程式支援 POSIX 參數語法-黑暗執行緒 昨天介紹了 POSIX 參數慣例,它是主流 CLI 工具一致遵守的參數語法規則,以 git 或 dotnet 為例,指令工具...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK