[英]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.