Batch file 在'for/F的'delims'选项中转义双引号`

Batch file 在'for/F的'delims'选项中转义双引号`,batch-file,escaping,Batch File,Escaping,批处理脚本需要将配置文件中的值解析为变量,我遇到了一些问题 适当地匿名,文件的相关行如下所示 <?define ProductShortName="Foo" ?> 主要是沿着 usebackq" %G in (`findstr /L "ProductShortName" "C:\foo\bar\Installer\Branding.wxi"`) was unexpected at this time. 在“”上拆分字符串的正确转义方法是什么?我还没有找到一种可行的方法。也许jeb

批处理脚本需要将配置文件中的值解析为变量,我遇到了一些问题

适当地匿名,文件的相关行如下所示

<?define ProductShortName="Foo" ?>
主要是沿着

usebackq" %G in (`findstr /L "ProductShortName" "C:\foo\bar\Installer\Branding.wxi"`) was unexpected at this time.

”上拆分字符串的正确转义方法是什么?

我还没有找到一种可行的方法。也许jeb插话时比我有更深入的知识。或者,使用
=
和空格作为分隔符切掉行,然后删除结果周围的引号:

for /f "tokens=3 usebackq delims== " %G in (`...`) do @echo %~G

我认为这是不可能的-引号(
)不能用作分隔符

但是,一种解决方案是将整行存储在一个环境变量中,并使用
set
的内置“replace”功能将报价替换为其他内容,例如
。然后,您可以在这一行上使用另一个for循环在新分隔符上拆分:

setlocal EnableDelayedExpansion
for /f "tokens=* usebackq" %%a in (`...`) do (
    set z=%%a
    set z=!z:"=_!
    for /f "tokens=1-3 delims=_" %%a in ("!z!") do echo %%b
)
一点解释。。。
的第一个
循环将整行内容放入
%a
变量中。然后将其复制到变量
z
<然后使用sets的内置搜索/替换功能再次设置code>z
(请注意,这里我们使用执行替换的
!z:=\u!
)引用变量)。最后,我们分析这一行以获得引号之间的项


我希望这有点道理。编辑:这是错误的,请稍后参阅我的评论: 正如Joey所说,似乎不可能将引用用作delim,它只能用作EOL角色。
这似乎是cmd.exe的FOR-LOOP解析器的作用,因为它扫描选项部分并在引号后停止扫描,只有EOL=选项打破了这一点,因为它总是读取下一个字符而没有任何预期

您可以使用icabod之类的解决方法来解决此问题。
解决方案是用一个未使用的字符替换引号,但是如果您想接受引号中的任何字符,就没有一个未使用的字符

因此,我的解决方案首先通过替换以前出现的所有字符来创建一个未使用的字符。
我想使用
来替换引号,但要保留引号内的所有
,请将其替换为
$R
,但是它可能会与文本中现有的
$R
冲突,因此我首先将所有
$
替换为
$D
,然后它是绝对无冲突的。
在提取“引用”文本后,我必须将$R和$D替换回它们的原始值,仅此而已

@echo off
setlocal EnableDelayedExpansion

for /F "tokens=1,2" %%1 in ("%% #") DO (
    for /f "tokens=* usebackq" %%a in ("datafile.txt") do (
        set "z=%%a"
        set "z=!z:$=$D!"
        set "z=!z:#=$R!"
        set "z=!z:"=#!"
        for /f "tokens=1-3 delims=#" %%a in ("!z!") do (
            set "value=%%b"
            if defined value (
                set "value=!value:$R=#!"
                set "value=!value:$D=$!"
                echo result='!value!'
            )
        )
    )
)
示例文本:

结果与预期一致

编辑:有办法!
我总是这样测试(但失败了)

但是去掉第一句话,它就行了

setlocal EnableDelayedExpansion
set "var=one"two"three"
FOR /f tokens^=1-3^ delims^=^" %%a in ("!var!") do echo %%a--%%b--%%c

您可以使用双引号作为分隔符,语法如下:

FOR /F delims^=^"^ tokens^=2 %G IN ('echo I "want" a "pony"') DO @ECHO %G
在命令行上运行时,使用
tokens^=2
应该会给您
want
,4个tokens会给您一匹小马

将该技术应用于原始问题,这应适用于批处理文件:

FOR /F delims^=^"^ tokens^=2 %%G IN ('FINDSTR /L "ProductShortName" "data.txt"')
详细信息

我不是这方面的专家,但想想通常的delims=blah tokens=blah可能会有所帮助“
作为传递给的单个组合参数。
delims^=blah^tokens^=blah
中的插入符号转义技巧绕过了封闭引号的需要,同时仍然将序列视为单个参数。我在这里使用了一些创造性的类比,这种效果在整个外壳中并不普遍。例如,您不能执行
dir C:^\Program^ Files
(这很有意义,因为
^
是一个有效的文件名字符)

测试用例

通过充分的转义,您可以在命令行上快速检查原始示例:

FOR /F delims^=^"^ tokens^=2 %G IN ('echo ^^^<?define ProductShortName="Foo" ?^^^>') DO @ECHO %G
然后运行类似于:

FOR /F delims^=^"^ tokens^=2 %G IN (testcases.txt) DO @ECHO %G
检查各种输入的结果。在这种情况下,它应产生:

red
green
white
最后一个例子:

FOR /F delims^=^"^ tokens^=2 %G IN ('FINDSTR /L "unicorn" "testcases.txt"') ^
DO @ECHO The unicorn is %G.

最后,请注意,我的测试是在Windows Server 2003上完成的。

我认为在后面的步骤中搜索引号周围的字符并去掉引号更容易。如果我们想从XML文件中的某一行提取值

<line x0="745" y0="1162" x1="1203" y1="1166"/>

一般来说,引号本身并不是真正的分隔符,因此在大多数情况下都可以这样做。

只要避免使用双引号,使用
^
转义字符串中的所有字符(包括空格)。这样,您可以添加双引号作为参数

for /F Tokens^=1^,2^-5^*^ Delims^=^" %%i in ( ...

这应该行得通。

幽默我,试试这个:
for/F“USEBACKQ tokens=3 delims==”%%G in(
findstr/L ProductShortName“%~dp0Installer\Branding.wxi”`)DO(SET var=%%~G)看起来是一个很有希望的方法,但我试图获得的值可能有空格。我将尝试使用
delims==?
执行此路线,然后在使用
%~
之前修剪空间。这就是目的;-)。虽然我现在想不出比替换引号并随后拆分(icabod的解决方案)或围绕引号拆分并删除它们更强大的方法了,但Google很快就找到了这个链接,它做了类似的事情,但将引号替换为
,可能有用:是的,这很有意义。我采用了Joey的方法,将
替换为空字符串,这更简单,但对空格更改的鲁棒性稍差。OP将此标记为答案,但这是错误的。正如下面两个例子中所解释的,有一种方法:使用^来转义等号、双引号以及标记和delim之间的空格。通过这样做,您可以删除整个tokens/delims参数周围的双引号。感谢您的回答,但我是否遗漏了什么,或者这与jeb的最终答案相同?事实上,这是相同的技术。我想也许我更清楚一点(目的是帮助未来的进步)
FOR /F delims^=^"^ tokens^=2 %G IN ('FINDSTR /L "unicorn" "testcases.txt"') ^
DO @ECHO The unicorn is %G.
<line x0="745" y0="1162" x1="1203" y1="1166"/>
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "tokens=3,5,7,9 delims==/ " %%i IN ('FINDSTR line %1') DO (
SET x0=%%~i
SET y0=%%~j
SET x1=%%~k
SET y1=%%~l
)
for /F Tokens^=1^,2^-5^*^ Delims^=^" %%i in ( ...