首页 > 解决方案 > 为什么不能在批量 for 循环中使用问号?

问题描述

前言

在编写一段单独的代码时,我遇到了 for 循环中的问号问题。如下图,for循环中没有访问到问号。

批处理文件:

@echo off

for %%x in (the, quick, ?, brown, fox) do (
    echo %%x
)

输出:

the
quick
brown
fox

这在 CMD 中也不起作用(使用%x而不是) ,%%x或者在使用"", [], ^,或其他常见的字符转义方法时。\%

使用计数器变量来确定括号内代码被访问的次数只会导致总计数为 4,这意味着它显然不是echo命令的问题。


问题

为什么问号在标准 for 循环中不起作用,我将如何修复它?

标签: windowsbatch-filefor-loopcmd

解决方案


这是因为?将扩展为一个字符长的文件名列表。“裸体”for使用该列表作为文件名列表。

如果您运行以下命令,您将看到这一点:

c:\> echo xx >a
c:\> echo xx >b
c:\> for %i in (1, ?) do echo %x
1
a
b

如果您查看Rob van der Woude 的优秀脚本页面,您会发现该for页面具有处理命令输出、数字和文件的选项——它并不真正适合任意字符串。

解决此问题的一种方法是提供您自己的 for-like 命令,如以下示例所示:

    @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

这提供了一个可以处理回调和简单命令的函数。对于更复杂的命令,提供一个回调函数,它会被每个参数依次调用。回调函数可以任意复杂,但请记住,因为它在 asetlocal中运行,所以对环境变量的更改无法转回给调用者。

作为解决此问题的一种方法,它允许一个变量 ,escapee转义范围 - 如果需要,您还可以添加更多。

echo对于只需要将参数放在末尾的简单命令(例如),您可以执行相同的操作。它不需要回调函数,但仅限于非常简单的场景。

还要记住,虽然这看起来像很多代码,但其中绝大多数只需要存在于一个地方。要使用它,您只需要像示例这样的单行代码:

call :doFor echo my hovercraft is full of eels

还要记住,即使使用此方案,也可能有其他角色表现不佳。它解决了?问题,但其他人可能仍然会导致问题。我怀疑这将是一个将 PowerShell 添加到您的 CV 的理想机会,例如,一个命令几乎bash就像它的优雅和禅宗一样:

PShell> foreach ($item in @("1", "?", "3", "4")) { echo $item }
1
?
3
4

推荐阅读