在编写单独的代码时,我在for循环中遇到了问号问题。如下所示,在for循环中不会访问问号。
批处理文件:
@echo off
for %%x in (the, quick, ?, brown, fox) do (
echo %%x
)
输出:
the
quick
brown
fox
此外,这不适用于CMD(当然使用%x
而不是%%x
),或者使用""
,[]
,{{1} },^
,\
或类似的字符转义方法。
此外,使用计数器变量来确定括号中的代码被访问的次数仅导致总数为4,这意味着%
命令显然不是问题。
为什么问号在这样的标准循环中不起作用,我该如何解决?
答案 0 :(得分:3)
这是因为?
将扩展为一个字符长的文件名列表。 “裸” for
使用该列表作为文件名列表。
如果运行以下命令,则会看到实际效果:
c:\> echo xx >a
c:\> echo xx >b
c:\> for %i in (1, ?) do echo %x
1
a
b
如果查看Rob van der Woude's excellent scripting pages,您会发现for
page具有用于处理命令输出,数字和文件的选项-它实际上并不适合于任意字符串。
一种解决方法是提供您自己的 own for
类似的命令,如以下示例所示:
@echo off
setlocal enableextensions enabledelayedexpansion
rem Call the callback function for each argument.
set escapee=/
call :doFor :processEach 1 2 ? 4 5
echo.Escapee was %escapee%
rem Execute simple command for each argument.
call :doFor echo 6 7 ? 9 10
endlocal
goto :eof
:processEach
set escapee=%escapee%%1/
goto :eof
:doFor
setlocal
rem Get action.
set cbAction=%1
shift
:dfloop
rem Process each argument with callback or command.
if not "%1" == "" (
call %cbAction% %1
shift
goto :dfloop
)
endlocal&&set escapee=%escapee%
goto :eof
这提供了一个可以处理回调和简单命令的功能。对于更复杂的命令,请提供一个回调函数,它将随每个参数依次调用。回调函数可以任意复杂,但是请记住,由于它在setlocal
中运行,因此对环境变量的更改无法逃逸回调用者。
为此,它允许一个变量escapee
逃脱作用域-您也可以根据需要添加更多内容。
对于简单的命令(例如echo
),您只需要在其末尾放置参数,即可执行相同的操作。它不需要回调函数,但仅限于非常简单的情况。
还要记住,尽管这看起来像很多代码,但绝大多数代码只需要存在于一个地方即可。要使用它,您只需要像示例一样的单线:
call :doFor echo my hovercraft is full of eels
还请记住,即使使用此方案,也可能会有 other 个字符表现不佳。它解决了?
问题,但其他问题仍然可能引起问题。我怀疑这是将PowerShell添加到您的简历中的理想机会,例如,该命令的优雅和禅意几乎与bash
类似:
PShell> foreach ($item in @("1", "?", "3", "4")) { echo $item }
1
?
3
4
答案 1 :(得分:1)
您可以切换到FOR /F
。
但是FOR / F用于处理多行以将其拆分为令牌。
如果您不需要多个令牌,则每个项目需要一个循环。
这可以通过使用换行符拆分项目来实现。
我使用#
作为项目分隔符,但您可以自由使用任何其他字符
@echo off
setlocal EnableDelayedExpansion
(set \n=^
%=EMPTY=%
)
set "itemList=the#quick#?#brown#fox"
for %%L in ("!\n!") DO (
FOR /F "delims=" %%x in ("!itemList:#=%%~L!") DO echo - %%x -
)
输出:
- the -
- quick -
- ? -
- brown -
- fox -
答案 2 :(得分:1)
我已经进行了很多年的编码工作,直到现在我都惊讶地意识到这个问题!
我找到了解决此问题的另一种方法。可能有人喜欢它,例如我。
在我特殊的情况下,我使用FOR LOOP获取当前函数的一些命名参数。这就是我所做的:
:SomeFunct
rem Replace ?
set "args=%*"
set "args=%args:?=`%"
rem Iterate args
for %%p in (%args%) do (
for /f "tokens=1,* delims=: " %%a in ("%%~p") do (
rem Get and store values
if /i "%%~a" equ "/a" set "argA=%%~b"
if /i "%%~a" equ "/b" set "argB=%%~b"
if /i "%%~a" equ "/c" set "argC=%%~b"
)
)
rem Restore ?
if defined argA set "argA=%argA:`=?%"
if defined argB set "argB=%argB:`=?%"
if defined argC set "argC=%argC:`=?%"
rem I use the args
rem ...
rem Return
goto:eof
我这样调用函数:
rem Calling example
call:SomeFunct "/a:Is there" "/b:a question mark" "/c in the arguments?"