简体   繁体   English

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

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

I have the following for command我有以下for命令

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

And I don't get it to work properly.我没有让它正常工作。 It is not the actual use-case, but a much simplified example.这不是实际用例,而是一个非常简化的示例。

Executing执行

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

works fine,工作正常,

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

says that the project direcotry "mass" does not exist (extra "s" for distinguisihing purpose only),表示项目目录“mass”不存在(额外的“s”仅用于区分目的),

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

says command "mas" was not found.说没有找到命令“mas”。

So far so expected, but now I want to get it working in the for loop.到目前为止是预期的,但现在我想让它在 for 循环中工作。

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

of course says again that command "mas" was not found,当然再次说没有找到命令“mas”,

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

of course says again that project direcotry "mass" does not exist but now it comes,当然再次说项目目录“质量”不存在但现在它来了,

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

again says that command "mas" was not found.再次说没有找到命令“mas”。 o_O o_o

And now I'm at wtf.现在我在wtf。
Why is this happening and how do I make it work?为什么会发生这种情况,我该如何让它发挥作用?
It also does not work to escape the spaces with ^ characters.^字符转义空格也不起作用。
Besides that, this wouldn't help, because the two paths are stored in parameters and are used like除此之外,这无济于事,因为这两个路径存储在参数中,并且像

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

This was really a frustrating one because the parsing of command is weird这真的很令人沮丧,因为命令的解析很奇怪

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

But you can't have double quotes in both first and any other param但是你不能在 first 和任何其他参数中都有双引号

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

Something of below would work fine下面的东西可以正常工作

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

So I came with few things for this to work所以我带着一些东西来让它起作用

par ams.bat参数.bat

A file with space in name and echo each parameter.名称中带有空格并回显每个参数的文件。 I also create copy of same as params.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

This shows what I need to do.这表明我需要做什么。

Now a file to test the setup现在是一个用于测试设置的文件

@echo off

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

this worked great这很好用

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

Next was to try par ams.bat .接下来是尝试par ams.bat I tried different variations我尝试了不同的变化

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

And none of the above worked.以上都没有奏效。 So the conclusion was that first param without space and then any param with space or quotes, no issues.所以结论是第一个没有空格的参数,然后是任何带有空格或引号的参数,没有问题。 So I came up with a additional batch file所以我想出了一个额外的批处理文件

escape.bat逃脱.bat

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

The file does nothing but takes first parameter as what to execute and then command line arguments for the same.该文件只将第一个参数作为要执行的内容,然后将命令行参数作为相同的参数。 And now I updated the test to use现在我更新了测试以使用

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

And then it worked然后它起作用了

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

Edit-1: Using call instead of escape.bat编辑 1:使用 call 而不是 escape.bat

Thanks for the feedback on this @Vampire.感谢您对此@Vampire 的反馈。 So a better way is to use call instead of a escape.bat .所以更好的方法是使用call而不是escape.bat Also you can get the script directory using set script_dir=%~dp0 and then use the same in your batch file.您也可以使用set script_dir=%~dp0获取脚本目录,然后在批处理文件中使用相同的目录。 So we will change所以我们会改变

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

to

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

Executive summary:执行摘要:

Enclose the command string in another set of double-quotes regardless of whether or not quotes are used in the command string (just leave those alone):无论命令字符串中是否使用引号,将命令字符串括在另一组双引号中(只管保留它们):

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

tl;dr details: tl;博士详细信息:

It appears that the for /f ... ('command') variant just passes the command string to cmd /c (or some equivalent internal code) to actually run the command.看来for /f ... ('command')变体只是将命令字符串传递给cmd /c (或某些等效的内部代码)以实际运行命令。

In general, cmd.exe has complicated, haphazard, and buggy quote handling rules.通常,cmd.exe 具有复杂、随意且有缺陷的报价处理规则。 The particular rules for cmd /c includes these copied from cmd /? cmd /c的特定规则包括从cmd /? help text:帮助文字:

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.

(who came up with that stuff?) (这东西是谁想出来的?)

What this boils down to for me is that it's best just to enclose the command string in a set of double-quotes regardless of whether or not quotes are used in the command string (just leave those alone).对我来说,这归结为最好将命令字符串括在一组双引号中,而不管命令字符串中是否使用了引号(不要管它们)。

Here's a batch file that is in a path containing a space - mas ter\\gradlew.bat :这是位于包含空格的路径中的批处理文件 - mas ter\\gradlew.bat

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

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

Here's a run of that batch file without the for loop:这是一个没有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"

And here is it used in a for loop with an enclosing set of double-quotes::这是它在带有一组封闭双引号的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