簡體   English   中英

如何在 Windows 上的“for /F”循環命令中引用空格

[英]How to quote spaces in the command of a “for /F” loop on Windows

我有以下for命令

for /F %s in ('"mas ter\gradlew.bat" -q -p mass ter') do echo %s

我沒有讓它正常工作。 這不是實際用例,而是一個非常簡化的示例。

執行

"mas ter\gradlew.bat" -q -p "mas ter"

工作正常,

"mas ter\gradlew.bat" -q -p mass ter

表示項目目錄“mass”不存在(額外的“s”僅用於區分目的),

mas ter\gradlew.bat -q -p mass ter

說沒有找到命令“mas”。

到目前為止是預期的,但現在我想讓它在 for 循環中工作。

for /F %s in ('mas ter\gradlew.bat -q -p mass ter') do echo %s

當然再次說沒有找到命令“mas”,

for /F %s in ('"mas ter\gradlew.bat" -q -p mass ter') do echo %s

當然再次說項目目錄“質量”不存在但現在它來了,

for /F %s in ('"mas ter\gradlew.bat" -q -p "mass ter"') do echo %s

再次說沒有找到命令“mas”。 o_o

現在我在wtf。
為什么會發生這種情況,我該如何讓它發揮作用?
^字符轉義空格也不起作用。
除此之外,這無濟於事,因為這兩個路徑存儲在參數中,並且像

for /F %s in ('"%script_path%\gradlew.bat" -q -p "%script_path%"') do echo %s

這真的很令人沮喪,因為命令的解析很奇怪

('"mas ter\gradlew.bat" -q -p mass ter')

但是你不能在 first 和任何其他參數中都有雙引號

('"mas ter\gradlew.bat" -q -p "mass ter"')

下面的東西可以正常工作

('master\gradlew.bat -q -p mass ter')

所以我帶着一些東西來讓它起作用

參數.bat

名稱中帶有空格並回顯每個參數的文件。 我還創建了與params.bat相同的副本

@echo off
setlocal enabledelayedexpansion
echo "You sent '%*'"
set argC=0
for %%x in (%*) do (
    Set /A argC+=1
    echo !argC! is %%x
)
echo %argC%

F:\params.sh>"par ams.bat" 1 2 "ab c"
"You sent '1 2 "ab c"'"
1 is 1
2 is 2
3 is "ab c"
3

這表明我需要做什么。

現在是一個用於測試設置的文件

@echo off

for /F "tokens=* delims=" %%s in (params.bat " -q" "  -p " "abc"`) do echo %%s

這很好用

"You sent '" -q" "  -p " "abc"'"
0 is " -q"
0 is "  -p "
0 is "abc"
3

接下來是嘗試par ams.bat 我嘗試了不同的變化

for /F "tokens=* delims=" %%s in ('par ams.bat " -q" "  -p " "abc"') do echo %%s
for /F "tokens=* delims=" %%s in ('"par ams.bat" " -q" "  -p " "abc"') do echo %%s
for /F "tokens=* delims=" %%s in ('par ams.bat' " -q" "  -p " "abc"') do echo %%s
for /F "tokens=* delims= usebackq" %%s in (`'par ams.bat' " -q" "  -p " "abc"`) do echo %%s
for /F "tokens=* delims= usebackq" %%s in (`"par ams.bat" " -q" "  -p " "abc"`) do echo %%s

以上都沒有奏效。 所以結論是第一個沒有空格的參數,然后是任何帶有空格或引號的參數,沒有問題。 所以我想出了一個額外的批處理文件

逃脫.bat

@echo off
SET COMMAND=%~1
SHIFT
%COMMAND %%*

該文件只將第一個參數作為要執行的內容,然后將命令行參數作為相同的參數。 現在我更新了測試以使用

for /F "tokens=* delims=" %%s in ('escape.bat "par ams.bat" " -q" "  -p " "abc"') do echo %%s

然后它起作用了

F:\params.sh>test
"You sent '" -q" "  -p " "abc"'"
0 is " -q"
0 is "  -p "
0 is "abc"
3

編輯 1:使用 call 而不是 escape.bat

感謝您對此@Vampire 的反饋。 所以更好的方法是使用call而不是escape.bat 您也可以使用set script_dir=%~dp0獲取腳本目錄,然后在批處理文件中使用相同的目錄。 所以我們會改變

for /F "tokens=* delims=" %%s in ('escape.bat "par ams.bat" " -q" "  -p " "abc"') do echo %%s

set script_name=%~dp0
for /F "tokens=* delims=" %%s in ('call "%script_name%\par ams.bat" " -q" "  -p " "abc"') do echo %%s

執行摘要:

無論命令字符串中是否使用引號,將命令字符串括在另一組雙引號中(只管保留它們):

for /F %s in ('""%script_path%\gradlew.bat" -q -p "%script_path%""') do echo %s

tl;博士詳細信息:

看來for /f ... ('command')變體只是將命令字符串傳遞給cmd /c (或某些等效的內部代碼)以實際運行命令。

通常,cmd.exe 具有復雜、隨意且有缺陷的報價處理規則。 cmd /c的特定規則包括從cmd /? 幫助文字:

the following logic is used to process quote (") characters:

    1.  If all of the following conditions are met, then quote characters
        on the command line are preserved:

        - no /S switch
        - exactly two quote characters
        - no special characters between the two quote characters,
          where special is one of: &<>()@^|
        - there are one or more whitespace characters between the
          two quote characters
        - the string between the two quote characters is the name
          of an executable file.

    2.  Otherwise, old behavior is to see if the first character is
        a quote character and if so, strip the leading character and
        remove the last quote character on the command line, preserving
        any text after the last quote character.

(這東西是誰想出來的?)

對我來說,這歸結為最好將命令字符串括在一組雙引號中,而不管命令字符串中是否使用了引號(不要管它們)。

這是位於包含空格的路徑中的批處理文件 - mas ter\\gradlew.bat

@echo off
echo "Running '%~dpnx0'"

:echo_args
    if "" == "%1" goto :eof
    echo arg: %1
    shift

這是一個沒有for循環的批處理文件的運行:

C:\temp>"mas ter\gradlew.bat" -q -p "mass ter"
"Running 'C:\temp\mas ter\gradlew.bat'"
arg: -q
arg: -p
arg: "mass ter"

這是它在帶有一組封閉雙引號的for循環中使用的:

C:\temp>for /F "tokens=*" %s in ('""mas ter\gradlew.bat" -q -p "mass ter""') do @echo from the for loop: "%s"
from the for loop: ""Running 'C:\temp\mas ter\gradlew.bat'""
from the for loop: "arg: -q"
from the for loop: "arg: -p"
from the for loop: "arg: "mass ter""

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM