批处理文件:在for循环中转义问号

3

以下是简化的最小示例for循环代码:

@echo off
for %%a in (help -help --help /help ? /?) do ( 
   echo %%a 
)

在含有'?'字符的2个元素中出现了故障。输出结果为:
C:\Temp>test.bat
help
-help
--help
/help

C:\Temp>

当程序遇到第一个问号 "?" 时,它就退出了循环。

这个字符集的正确转义序列是什么?我试过很多东西,双引号、插入符号、反斜杠等等,但好像都没有生效。

4个回答

5

另一种选择是在 FOR /F 字符串中使用换行符。FOR /F 将每行视为独立的字符串。下面我展示了四种实现相同效果的方法。

@echo off
setlocal enableDelayedExpansion

:: Define LF to contain a linefeed character
set ^"LF=^

^" The above empty line is critical. DO NOT REMOVE

:: Option 1
:: Embed linefeeds directly in the string literal
for /f %%A in ("help!LF!-help!LF!--help!LF!/help!LF!?!LF!/?") do (
  echo(%%A
)


echo(
:: Option 2
:: Define a variable with spaces and use search and replace
:: to substitue linefeeds
set "help=help -help --help /help ? /?"
for %%L in ("!LF!") do for /f %%A in ("!help: =%%~L!") do (
  echo(%%A
)


echo(
:: Option 3
:: Embed linefeed directly in string without LF variable
for /f %%A in (^"help^

-help^

--help^

/help^

?^

/?^") do (
  echo(%%A
)


echo(
:: Option 4
:: Embed linefeed directly in search and replace without LF variable
for /f %%A in (^"!help:^ ^=^

!^") do (
  echo(%%A
)

我更倾向于选项2,我觉得它既易于阅读,又紧凑。

请注意,MC ND和我都使用echo(%%A。这是为了防止echo /?显示ECHO命令的帮助信息。


+1。另一个:for %%L in (^"^ - 此处留空 - ^") do for /f %%A in ("!help: =%%~L!") do ( - echo(%%b - ) - Aacini
糟糕!先前的 echo(%%b 应该是 echo(%%A ... ;-) - Aacini
@dbenham 谢谢,那个方法可行!我使用的是选项2。 - Tieske

2
没有任何东西能起作用,因为没有一样东西会起作用。 for %%x in (set) do ...是最简单的形式,当for命令遍历集合中的元素时,它将测试该元素是否包含*?。在这种情况下,它被视为文件通配符,并将搜索与指定表达式匹配的文件。您可以在放置一个没有扩展名的单个字符名称的文件的批处理文件所在的文件夹中测试它,?将与它匹配并显示在输出中。
据我所知,没有办法避免这种情况。这就是for命令的工作方式。
您可以构建类似于您尝试的内容,但需要采用另一种方法。
@echo off
    setlocal 

    set "opt.a=help" 
    set "opt.b=-help"
    set "opt.c=--help"
    set "opt.d=/help"
    set "opt.e=?"
    set "opt.f=/?"

    for /f "tokens=2 delims==" %%a in ('set opt.') do ( 
       echo(%%a 
    )

    endlocal

在此示例中,每个值都在环境变量中,并且该集合通过set命令检索并使用for命令的选项进行处理输出。这是一种选择。您需要将值作为以换行符分隔的字符串处理,以便使用for /f进行处理。

1

尽管我个人认为dbenham提供了最好的答案, 但我想补充一下,在某些情况下,应该为FOR /F循环提供选项:

  1. tokens=* - 这将禁用行的标记化(或者在您需要时,您可以将delims设置为任何您想要的),从而允许您在字符串中使用空格;
  2. usebackq - 这将允许您在字符串中使用双引号。但是,在这种情况下,单引号需要用脱字符进行转义- ^',并且周围的双引号应替换为单引号:
(set RN=^
%= \r\n =%
)
for /f "usebackq tokens=*" %%A in ('^'quotes^'!RN!"double quotes"!RN!`backquotes`') do (
  echo:%%A
)

关于原问题,还有其他几个选项可用。Alex的回答 (链接) 有点意思,但它没有涵盖如何实际迭代列表。要做到这一点,您需要链接 echo 命令。您可以从 echo: 开始,并使用 ^&echo: 来链接所有后续字符串/变量:
set "var=line1"
for /F "usebackq delims=" %%G in (`
echo:%var%^&
echo:   line2 * ? ^^^^ ^^^& ^^^< ^^^> ^^^| ^^^" ' ^` ^)   ^&
echo: ^ ^ line3 ^ ^ ^&echo:li

ne4^&echo  ^&echo: ^&echo:/?
`) do (
    echo "%%G"
)

这将给你:
"line1"
" line2 * ? ^ & < > | " ' ` ) "
"   line3   "
"li ne4"
"ECHO is on."  # System language specific
" "
"/? "

  • 如图所示,您可以以任何方式断行,只要保持^&echo:不变(注意空格)。
  • echo之后使用冒号而不是空格将消毒诸如ONOFF /?之类的值。您还可以使用其他一些字符,例如(,但我认为冒号更易读。
  • 允许换行,但所有连续的空格(空格和换行符)都将替换为单个空格(可以通过用单个脱字符^转义它们来强制额外的空格)。echo ^&将计为没有参数的echo并显示当前的echo设置,echo:^&将给出一个空行(FOR / F忽略空行),echo: ^&将给你
  • ^ & < > | "需要用三个脱字符进行转义。 ` )需要用单个脱字符进行转义。
  • 如果没有usebackq选项,则无需转义`,但您需要使用三个脱字符转义'。您还需要使用单引号而不是包围反引号。

如果您将表达式放在双引号内,就可以避免过度转义,如下所示:

for /f "usebackq delims=" %%G in (`"echo:%var%&echo:   line2 * ? ^^ ^& ^< ^> ^| ' ` "abc" ^)   &echo &echo: &echo:/?"`) do (
    echo "%%G"
)

这将会给你:
"line1"
"   line2 * ? ^ & < > | ' ` "abc" )   "
"ECHO is on."  # System language specific
" "
"/?"
  • 要链接echo命令,您需要使用&echo:(注意,没有脱字符)。
  • 不允许换行。空格将被保留。
  • "无法转义,但如果它们成对出现,则可以使用。您不需要转义'`
  • 同样,如果没有usebackq选项,则需要使用单引号而不是反引号。

-1

如果您使用 for /f 循环,它可以在不转义 ? 字符的情况下工作,尽管循环的工作方式不同:

C:\Users\Alex\Downloads\test>for /f "tokens=* delims=" %a in ('echo help -help --help /help ? /?') do echo %a

C:\Users\Alex\Downloads\test>echo help -help --help /help ? /?
help -help --help /help ? /?

2
我不明白这如何帮助迭代列表? - Tieske
1
以任何方式都不一样 - paxdiablo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接