Windows 命令列 ImageMagick 百分比轉義

Windows 命令列 ImageMagick 百分比轉義

我正在嘗試從 Windows 7 的命令列使用 ImageMagick 一次轉換許多圖像。我想使用 -set 選項介面,但我得到了意想不到的結果。我看到的一些奇怪現象的一個簡短例子是:

C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world "%[filename:foo]_%[filename:bar].png"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.135

請注意,下劃線字元被神秘地從輸出檔案名稱中刪除。我可以使用脫字號 (^) 轉義第二個百分號以保留下劃線:

C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world "%[filename:foo]_^%[filename:bar].png"
example.jpg=>hello_world.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.126

這裡發生了什麼事?為什麼插入插入符號會導致保留下劃線?插入符號 (^) 是否是要嘗試的正確轉義符?這種行為是由於命令 shell 環境變數擴展造成的,還是由於 ImageMagick 處理百分比轉義的方式導致的?無論哪種方式,是否有關於在命令列參數中使用百分號符號的一般原則,可以遵循這些原則來導致可預測的行為?

我實際上想做的是設定了更多屬性的上述命令的版本,它可以處理帶有空格和百分號等特殊字元的文件名,但如果我無法理解這個更簡單的範例,那麼嘗試這樣做似乎很愚蠢。最終,我需要從 .NET 程式執行該命令。

我看過http://www.robvanderwoude.com/escapechars.php在命令列中轉義文件/資料夾名稱中的 %但無法弄清楚如何將建議應用於我的問題。

更新

添加更多示例來回答 @dbenham 和 @Synetech 評論中的問題。

將下劃線從第二個百分號之前(如上面的後一個範例所示)移到下劃線之前,會產生一個名為 的檔案hello^world.png

C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world "%[filename:foo]^_%[filename:bar].png"
example.jpg=>hello^world.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.141u 0:00.132

插入符號轉義周圍的引號總是會導致helloworld.png,無論插入符號位於何處:

C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"^%[filename:foo]_^%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.109u 0:00.115

C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"%[filename:foo]_^%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.141u 0:00.143

C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"^%[filename:foo]_%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.126

C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"%[filename:foo]_%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.131

C:\>convert example.jpg -verbose -set filename:foo hello -set filename:bar world ^"%[filename:foo]^_%[filename:bar].png^"
example.jpg=>helloworld.png JPEG 352x264 352x264+0+0 8-bit DirectClass 131KB 0.125u 0:00.111

答案1

我無法完全解釋你所看到的奇怪行為。它幾乎看起來像是 cmd.exe 百分比處理的結果,但它與我理解的 cmd.exe 行為並不完全匹配。

在批次檔中轉義百分比很容易 - 只需將它們加倍即可。但這在命令列中不起作用。從技術上講,無法在 Windows cmd.exe 命令列上轉義百分比。

命令列可以透過以下兩種方式之一擴展百分比:

1) 展開環境變數。

如果兩個百分比之間的文字與環境變數的名稱匹配,則百分比結構將替換為該值。

C:\test>set test=hello

C:\test>echo %test%
hello

如果百分比之間的文字與環境變數名稱不匹配,則保留完整的原始文字。

C:\test>echo %notDefined%
%notDefined%

微軟自己的文件聲稱您可以透過在前面添加插入符號來轉義百分比。

C:\test>echo ^%test^%
%test%

但這並沒有真正逃脫百分比。相反,它正在尋找名為 的變量test^,但沒有找到。所以原文沒有受到干擾。然後在正常的轉義處理過程中刪除插入符號。這可以透過定義名稱中帶有插入符號的變數來證明。

C:\test>set "test^=goodbye"

C:\test>echo ^%test^%
goodbye

第一個百分比之前的插入符號不執行任何操作。您可以在百分號之間的任何位置放置插入符號,只要名稱中不存在帶有插入符號的變量,它就會阻止變數擴展。

C:\test>echo %te^st%
%test%

如果文字被引用,那麼插入符號就不會被刪除,除非引號也被轉義。

C:\test>echo "%te^st%"
"%te^st%"

C:\test>echo ^"te^st%^"
"%test%"

當有冒號時,情況會稍微複雜一些。變數擴充使用冒號進行替換和子字串操作。變數名稱是第一個百分號和冒號之間的文字。

C:\test>echo %test:el=a%
halo

C:\test>echo %test:~1,2%
el

如果第一個百分比和冒號之間的文字與變數名稱不匹配,或者冒號和最後一個百分比之間的文字不是有效的替換或子字串構造,則保留原始文字而不進行替換。

C:\test>echo %test:1,2%
%test:1,2%

最後一個例子最接近您的情況。第一個百分比和冒號之間的文字與變數不匹配,冒號和最後一個百分比之間的文字不是替換或子字串構造,所以整個結構應該要保留,包括底線。因此,我不明白 cmd.exe 如何刪除你的底線。但事實上,在第二個百分比之前添加插入符號會保留下劃線,這讓我感到懷疑。我真的很想知道如果將插入符號移到下劃線之前會發生什麼。


2) 展開FOR變數

在您的情況下這不是問題,但如果 FOR 迴圈有效,百分比也可能導致問題。在這種情況下,無法透過使用插入符號來保護百分比,因為插入符號在 FOR 變數擴展之前被刪除。在此範例中,我希望輸出為 read %A=1,但它不起作用。

C:\test>for %A in (1 2) do @echo ^%^A=%A
1=1
2=2

保護百分比最方便的方法是引入另一個 FOR 變數

C:\test>for %C in (%) do @for %A in (1 2) do @echo %CA=%A
%A=1
%A=2

A將其放入另一個變數中也同樣有效

C:\test>for %C in (A) do @for %A in (1 2) do @echo %%C=%A
%A=1
%A=2

更新

測試下劃線被刪除的位置的一個好方法是將 ECHO 放在命令之前。如果原始命令保留有下劃線,那麼您就知道轉換實用程式一定是罪魁禍首。

C:\>echo convert example.jpg -verbose -set filename:foo hello -set filename:bar world "%[filename:foo]_%[filename:bar].png"

底線保留在我的機器上:-)


如果您對命令解析器的工作原理進一步感興趣,請參閱https://stackoverflow.com/a/4095133/1012053。這個答案主要涉及批量解析,但規則非常相似,最後的一節簡要描述了主要差異。

相關內容