如何在for循环中处理路径名中的右括号? [英] How to handle a closing parenthesis in path names in a for loop?

查看:98
本文介绍了如何在for循环中处理路径名中的右括号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于要在/f循环中运行的程序,我有一个很长的路径名,其中包括右括号)",并且需要从中解析输出:

I have a long path name to a program I must run in a for /f loop, which includes a closing parenthesis ")", and from which I need to parse the output:

for /f "tokens=1" %%G in ('"C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe" list') do (echo Will do something with %%G)

...其中列表"是传递给我的程序的参数.我收到错误消息'C:\ Documents'无法识别为内部或外部命令,可操作程序或批处理文件."

...where 'list' is a parameter passed to my program. I get the error "'C:\Documents' is not recognized as an internal or external command, operable program or batch file."

我知道问题是闭合括号实际上关闭了"for"块,因此结尾的双引号不是"seen",因此长路径名未包含在double内报价了.我不明白为什么会这样,因为我的路径用双引号括起来了?我也尝试过usebackq选项:

I do know the problem is that the closing parenthesis in fact closes the "for" block, so the ending double quotes is not "seen", so the long path name is not enclosed within double quotes anymore. What I don't understand is why is this happening, since my path is enclosed within double quotes? I also tried the usebackq option:

for /f "usebackq tokens=1" %%G in (`"C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe" list`) do (echo Will do something with %%G)

...没有更好的结果.我试图像这样的"^)"或这样的"^^)"那样逃避,无所事事.尝试将双引号加倍:

...with no better results. I tried to escape like this "^)" or like this "^^)", nothing to do. Tried doubling the double quotes:

for /f "tokens=1" %%G in ('""C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe"" list') do (echo Will do something with %%G)

仍然无法正常工作.

此外,我实际上是使用一个保存路径的变量,该变量是事先不知道的(由%CD%构建),并且已激活 EnableDelayedExpansion .我尝试了延迟扩展(在其他情况下确实解决了类似问题),以防止变量在读取时扩展,并在执行时延迟:

I'm, furthermore, in fact using a variable that holds the path, which is not know in advance (built from %CD%), and EnableDelayedExpansion is activated. I tried the delayed expansion (which did fixed similar problems in other situations) to prevent the variable's expansion at read time and delay it at execution time:

setlocal EnableDelayedExpansion
set _var=%CD%\program.exe
@REM _var now contains C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe
for /f "tokens=1" %%G in ('"!_var!" list') do (echo %%G)
endlocal

还是不行,不明白为什么.

Still doesn't work, don't understand why.

但是,在上述代码中,双引号加倍,延迟扩展:

But, doubling the double quotes with delayed expansion in above code:

for /f "tokens=1" %%G in ('""!_var!"" list') do (echo %%G)

有效! ...为什么...为什么必须这样做???它有什么作用?我不明白我还担心在某些特定情况下可能会引起问题...

does work!... why... why having to do this??? What effect does it have? I don't understand. I also fear it may cause a problem in some specific circumstances...

有什么主意吗?

推荐答案

此问题答案中的注释表明XP提供了与新版Windows不同的行为.

Comments in the answers to this question indicate XP gives different behavior then newer Windows versions.

XP中存在一个已知的FOR/F错误: http://www.dostips.com/forum/viewtopic.php?p=9062#p9062 .但是此问题与该错误无关.

There is a known FOR /F bug in XP: http://www.dostips.com/forum/viewtopic.php?p=9062#p9062. But this problem is not related to that bug.

实际问题源于FOR/F如何在IN()子句中执行命令.它使用CMD \C command(请参阅如何Windows命令解释器(CMD.EXE)解析脚本吗?)

The actual problem stems from how FOR /F executes a command in the IN() clause. It uses CMD \C command (See How does the Windows Command Interpreter (CMD.EXE) parse scripts?)

您可以通过将这一行添加到Aacini的PROG.BAT示例中来观察这种行为.

You can observe this behavior by adding this line to Aacini's PROG.BAT example.

echo cmdcmdline=%cmdcmdline%

下一期将讨论CMD如何处理/C命令中出现的引号,以及为什么XP的行为与最新的Windows版本有所不同.

The next issue deals with how CMD deals with quotes that appear in the /C command, and why XP behaves differently than more recent Windows versions.

此命令在XP中失败,但在Vista及更高版本中成功:

This command fails in XP, but succeeds in Vista and beyond:

for /f "delims=" %a in ('"test (this)\prog" args') do @echo %a

FOR尝试执行的命令(%cmdcmdline%)在两个版本中都是相同的(忽略%COMSPEC%的差异):

The command that FOR tries to execute (%cmdcmdline%) is the same in both versions (disregarding differences in %COMSPEC%):

C:\Windows\system32\cmd.exe /c "test (this)\prog" args

XP在如何处理报价方面存在CMD设计缺陷.甚至会记录该缺陷(但不能识别为缺陷). Vista及更高版本部分修复了设计缺陷,但不必费心去纠正文档.

XP has a CMD design flaw in how it deals with the quotes. The flaw is even documented (but it is not recognized as a flaw). Vista and beyond partially fix the design flaw, but don't bother to correct the documentation.

这是HELP CMD的摘录

Here is an excerpt from HELP CMD

If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where 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.

我们希望CMD遵循规则1,以便保留引号,但()违反XP上的特殊字符约束,因此遵循规则2,CMD尝试执行

We want CMD to follow rule 1 so that quotes are preserved, but ( and ) violate the special character constraint on XP, so rule 2 is followed and the CMD tries to execute

test (this)\prog args

这很明显为什么会失败!

It should be fairly obvious why this fails!

我想不出规则1中存在特殊字符约束的任何原因,这违背了MS试图做的全部目的.

I can't think of any reason why the special character constraint exists in rule 1. It defeats the whole purpose of what MS is attempting to do.

显然,Vista及更高版本中的设计缺陷已部分修复,但他们尚未更新HELP文档. Vista将忽略特殊字符(),并使用规则1处理命令,保留引号,然后一切正常.

Apparently the design flaw is partially fixed in Vista and beyond, but they haven't updated the HELP documentation. Vista ignores the special characters ( and ) and processes the command using rule 1, the quotes are preserved, and everything works.

更新2015-05-17: 不幸的是,Vista及更高版本仍将@^&视为特殊字符,即使它们是文件名中的有效字符.当然,<>|被视为特殊字符,但无论如何它们在文件名中均无效.因此,对于Vista和更高版本,规则1的文档应阅读 where special is one of: &<>@^|.

Update 2015-05-17: Unfortunately, Vista and beyond still treat @, ^, and & as special characters, even though they are valid characters within file names. Of course <, >, and | are treated as special characters, but they are not valid in a file name anyway. So for Vista and beyond, the documentation for rule 1 should read where special is one of: &<>@^|.

我已经跟踪了每个人都记录的行为,并且与上述行为完全一致.

I've traced the behavior that everyone has documented, and it is all consistent with the above.

有一种方法可以在XP上执行命令而无需使用延迟的扩展变量,并且与Vista及更高版本兼容.

There is a way to execute the command on XP without using a delayed expansion variable, and it is compatible with Vista and beyond.

for /f "delims=" %a in ('^""test (this)\prog" args^"') do @echo %a

开头和结尾引号均被转义,以使)不会干扰FOR解析器.为IN()子句执行的命令是

The opening and closing quotes are escaped so that the ) does not interfere with the FOR parser. The command that is executed for the IN() clause is

C:\Windows\system32\cmd.exe /c ""test (this)\prog" args"

XP和Vista均遵循规则2,因为引号多于两个,因此CMD会执行

Both XP and Vista follow rule 2 because there is more than two quotes, so CMD executes

"test (this)\prog" args

一切正常!

此答案的其余部分已过时,但为了保留现有注释的上下文而保留.

The rest of this answer is outdated but preserved to give context to existing comments.

您的第一个代码示例应该可以工作;它不能(不应该这样做)给出您所描述的错误消息.错误消息在第一个空格处断开了路径,这意味着该路径未被引用或转义.但是您确信"它被引用了.

Your very 1st code example should work; it cannot (make that should not) give the error message you describe. The error message breaks off the path at the first space, which implies that the path was not quoted or escaped. But you are "sure" it was quoted.

该问题的关键是帖子结尾附近的三条信息:

The key to the problem is three pieces of information near the end of your post:

  1. 您实际上是 使用延迟扩展的变量

这不起作用:for /f "tokens=1" %%G in ('"!_var!" list') do (echo %%G)

这有效:for /f "tokens=1" %%G in ('""!_var!"" list') do (echo %%G)

如果var的值已被加引号,则您将得到所描述的行为.

If the value of var is already quoted, you will get the behavior you are describing.

您的var的值必须为"C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe",包括引号.

The value of your var must be "C:\Documents and Settings\myaccount\Desktop\Test_release (x86)\program.exe", including the quotes.

为使此说明更易读,我将缩短到"test (this)\prog.exe"

To make this explanation more readable I will shorten the path to "test (this)\prog.exe"

"!var!"失败,因为它扩展为""test (this)\prog.exe"",这实际上取消了路径的引用.字符串具有三个区域,两个区域用引号引起来,而一个区域的中间则没有:

"!var!" fails because it expands to ""test (this)\prog.exe"", which effectively unquotes the path. The string has three areas, two that are quoted, and one in the middle that is not:

"空引用区域"未引用路径"空引用区域"

"empty quoted area"unquoted path"empty quoted area"

""!var!""之所以起作用,是因为它扩展到了"""test (this)\prog.exe""",并且现在再次引用了该路径.字符串中现在有五个区域:

""!var!"" works because it expands to """test (this)\prog.exe""" and the path is now quoted again. There are now five areas within the string:

"空的报价区域"空的非报价区域"报价路径"空的非报价区域"空的报价区域"

"empty quoted area"empty unquoted area"quoted path"empty unquoted area"empty quoted area"

有关如何进行的简单答案:

The simple answer as to how you should proceed:

如果已经引用了var的值,则只需使用!var! Edit-在XP上不起作用:!var!"在这两者上都可以使用

If the value of var is already quoted, then simply use !var! Edit- that doesn't work on XP: "!var!" works on both

如果未引用var的值,则使用"!var!" Edit-在XP上不起作用:"!var!"在两者上均可

If the value of var is not quoted, then use "!var!" Edit- that doesn't work on XP: ""!var!"" works on both

这篇关于如何在for循环中处理路径名中的右括号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆