为什么不能在批处理 for 循环中使用问号? [英] Why can't you use a question mark in a batch for loop?
问题描述
前言
在编写单独的一段代码时,我遇到了 for 循环中的问号问题.如下图,for循环中没有访问问号.
批处理文件:
@echo off对于 %%x in (the, quick, ?, brown, fox) 做 (回声%%x)
输出:
快的棕色的狐狸
这在 CMD 中也不起作用(使用 %x
而不是 %%x
),或者在使用 ""
时、[]
、^
、\
、%
或其他常用的字符转义方法.
使用计数器变量来确定访问括号内代码的次数只会导致总计数为 4,这意味着 echo
命令显然没有问题.>
问题
为什么问号在标准 for 循环中不起作用,我该如何解决?
这是因为 ?
将被扩展为一个长度为一个字符的文件名列表.裸"for
使用该列表作为文件名列表.
如果您运行以下命令,您将看到此操作:
c:\>回声 xx >ac:\>回声 xx >bc:\>对于 (1, ?) 中的 %i 做 echo %x1一种乙
如果您查看 Rob van der Woude 出色的脚本页面,您会看到 for
页面 有用于处理命令输出、数字和文件的选项 - 它不是非常适合任意字符串.
解决这个问题的一种方法是提供您自己的 for
类似命令,如下例所示:
@echo offsetlocal enableextensions enabledelayedexpansionrem 为每个参数调用回调函数.设置逃生=/调用 :doFor :processEach 1 2 ?4 5echo.Escapee 是 %escapee%rem 对每个参数执行简单命令.呼叫 :doFor echo 6 7 ?9 10本地端转到:eof:processEach设置逃生者=%逃生者%%1/转到:eof:做设置本地rem 采取行动.设置 cbAction=%1转移:dflooprem 使用回调或命令处理每个参数.如果不是 "%1" == "" (调用 %cbAction% %1转移转到:dfloop)endlocal&&set escapee=%escapee%转到:eof
这提供了一个可以处理回调和简单命令的函数.对于更复杂的命令,提供一个回调函数,它将依次使用每个参数调用.回调函数可以是任意复杂的,但请记住,因为它在 setlocal
中运行,对环境变量的更改无法返回给调用者.
作为一种解决方法,它允许一个变量,escapee
,转义范围 - 如果需要,您还可以添加更多.
对于简单的命令(比如 echo
),你只需要将参数放在最后,你做同样的事情.它不需要回调函数,但仅限于非常简单的场景.
还要记住,虽然这看起来像很多代码,但其中的绝大多数只需要存在于一个地方.要使用它,您只需要一个像示例一样的单线:
call :doFor echo 我的气垫船装满了鳗鱼
还要记住,即使采用这种方案,也可能存在 其他 字符表现不佳.它解决了 ?
问题,但其他人可能仍然会导致问题.我怀疑这将是将 PowerShell 添加到您的 CV 的理想机会,例如,一个几乎与 bash
类似的命令,它的优雅和禅意:
PShell>foreach ($item in @("1", "?", "3", "4")) { echo $item }1?34
Preface
While writing a separate piece of code, I encountered a problem with question marks in for loops. As shown below, the question mark is not accessed in the for loop.
Batch file:
@echo off
for %%x in (the, quick, ?, brown, fox) do (
echo %%x
)
Output:
the
quick
brown
fox
This also does not work in the CMD (using %x
instead of %%x
), or when using ""
, []
, ^
, \
, %
or other common methods of character escaping.
Using a counter variable to determine the number of times the code within the parentheses was accessed only results in a total count of 4, meaning it is clearly not a problem with the echo
command.
Question
Why doesn't a question mark work in a standard for loop, and how would I go about fixing it?
It's because ?
will be expanded into a list of filenames one character long. The "naked" for
is using that list as a list of filenames.
If you run the following commands, you'll see this in action:
c:\> echo xx >a
c:\> echo xx >b
c:\> for %i in (1, ?) do echo %x
1
a
b
If you look at Rob van der Woude's excellent scripting pages, you'll see that the for
page has options for processing command output, numbers and files - it's not really suited for arbitrary strings.
One way to get around that is to provide your own for
-like command as shown in the following example:
@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
This provides a single functions which can handle both callbacks and simple commands. For more complex commands, provide a callback function and it will get called with each argument in turn. The callback function can be arbitrarily complex but keep in mind that, because it's operating within a setlocal
, changes to environment variables cannot escape back to the caller.
As a way around this, it allows one variable, escapee
, to escape the scope - you could also add more if needed.
For simple commands (like echo
) where you just need the argument placed at the end, you do the same thing. It doesn't need a callback function but it's restricted to very simple scenarios.
Also keep in mind that, although this seems like a lot of code, the vast majority of it only needs to exist in one place. To use it, you simply need a one-liner like the sample:
call :doFor echo my hovercraft is full of eels
Also keep in mind that there may be other characters that do not fare well, even with this scheme. It solves the ?
issue but others may still cause problems. I suspect that this would be an ideal opportunity to add PowerShell to your CV, for example, a command that's almost bash
-like in it's elegance and zen-ness:
PShell> foreach ($item in @("1", "?", "3", "4")) { echo $item }
1
?
3
4
这篇关于为什么不能在批处理 for 循环中使用问号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!