【问题标题】:Double Expansion on Array Index Windows Batch数组索引 Windows Batch 的双重扩展
【发布时间】:2019-10-02 21:36:58
【问题描述】:

在 for 循环中,我试图访问索引为 count in CLs 的元素(这行代码:echo !!CLs[!count!]!!),但我不知道该怎么做。我真的不明白在这种情况下扩展是如何工作的,所以你在它下面看到的我不知道从哪里尝试一些东西。

@ECHO off
setlocal enableextensions enabledelayedexpansion

SET CLs[0]=#

SET /A count = 0
FOR /F "tokens=5" %%I IN ('some command') DO (
    echo !!CLs[!count!]!! :: THIS LINE
    IF NOT %%I == CLs[!count!] (
        SET /A count += 1
        SET CLs[!count!]=%%I 
    )
)

echo The item is %CLs[10]%
endlocal

谢谢

【问题讨论】:

  • 你试过Call Echo %%CLs[!count!]%%吗?
  • 这似乎是 X-Y 问题meta.stackexchange.com/questions/66377/what-is-the-xy-problem> 请发布您正在尝试解决的实际问题。您是否尝试在已建立的 CLs 数组中查找 %%I(不是批处理中的最佳名称,因为 cls 是关键字)或向数组 CLs 添加唯一实体或什么?
  • @Magoo 我正在尝试从命令输出中创建一个仅包含特定唯一标记的数组。这有帮助吗?

标签: arrays batch-file indexing cmd


【解决方案1】:

根据帖子How does the Windows Command Interpreter (CMD.EXE) parse scripts?(见第5阶段),echo !!CLs[!count!]!!行不能工作,因为开头的!!被折叠成一个!,然后!CLs[!被展开为一个空字符串(假设未定义此类变量),则按字面意思返回 count,然后将 !]! 扩展为空字符串,并取消最终的 !。或者换句话说,延迟扩展不能嵌套。

您可以使用call 来引入另一个解析阶段,如下所示:

call echo %%CLs[!count!]%%

IF NOT %%I == CLs[!count!] ( ... ) 行错误,你也必须扩展正确的值。但是,不幸的是,call if 将无济于事,因为if(如forrem)是解析器比其他命令更早识别的特殊命令,如call

要解决这个问题,您可以将!count! 的值存储在for 元变量中,例如%%J,以引入另一个解析阶段,然后使用!CLs[%%J]!,如下所示:

set /A "count=0"
for /F "tokens=5" %%I in ('some command') do (
    for %%J in (!count!) do (
        echo !CLs[%%J]!
        if not "%%I" == "!CLs[%%J]!" (
            set /A "count+=1"
            set "CLs[!count!]=%%I"
        )
    )
)

另一种较慢的可能性是将相关代码放入子例程中:

set /A "count=0"
for /F "tokens=5" %%I in ('some command') do (
    call :SUB !count!
)

goto :EOF


:SUB
    echo !CLs[%~1]!
    if not "%%I" == "!CLs[%~1]!" (
        set /A "count+=1"
        set "CLs[%~1]=%%I"
    )
    goto :EOF

您也可以看看Arrays, linked lists and other data structures in cmd.exe (batch) script 的帖子,了解如何处理此类伪数组。

【讨论】:

    【解决方案2】:
    ECHO ------------- START AT %time%
    
    REM <!-- language: lang-dos -->
    @ECHO Off
    setlocal enableextensions ENABLEDELAYEDEXPANSION
    
    SET "sourcedir=U:\sourcedir"
    SET "filename1=%sourcedir%\q58209698.txt"
    
    SET CLs[0]=#
    SET /a clscnt[0]=0
    
    SET /A count = 0
    FOR /F "tokens=*" %%I IN ('type %filename1%') DO (
     SET "processed="
     FOR /f "tokens=1,2,3delims=[]=" %%a IN ('set cls[') DO IF /i "%%a"=="cls" (
      IF "%%I"=="%%c" (SET /a clscnt[%%b]+=1&SET "processed=y")
     )
     IF not DEFINED processed SET /a count+=1&SET "cls[!count!]=%%I"&SET /a clscnt[!count!]=1
    )
    
    FOR /L %%a IN (0,1,%count%) DO ECHO !clscnt[%%a]! times !cls[%%a]!
    
    ENDLOCAL
    ECHO -------------------------Second way -----------------
    @ECHO Off
    setlocal enableextensions ENABLEDELAYEDEXPANSION
    
    SET "sourcedir=U:\sourcedir"
    SET "filename1=%sourcedir%\q58209698.txt"
    
    SET CLs[0]=#
    SET /a clscnt[0]=0
    
    SET /A count = 0
    FOR /F "tokens=*" %%I IN ('type %filename1%') DO (
     SET "processed="
     FOR /L %%a IN (0,1,!count!) DO (
      IF "%%I"=="!cls[%%a]!" (SET /a clscnt[%%a]+=1&SET "processed=y")
     )
     IF not DEFINED processed SET /a count+=1&SET "cls[!count!]=%%I"&SET /a clscnt[!count!]=1
    )
    
    FOR /L %%a IN (0,1,%count%) DO ECHO !clscnt[%%a]! times !cls[%%a]!
    
    ENDLOCAL
    
    GOTO :EOF
    

    我使用了一个名为 q58209698.txt 的文件,其中包含一些用于我的测试的虚拟数据,并选择使用整个数据行,在 token 5 存在的地方没有合适的文件。

    请注意,作为奖励,我添加了 clscnt - 一个出现计数数组。

    显示:实现查找/计算唯一令牌目标的两种不同方法。当然,如果 cls 数组预先加载了所需的令牌,那么基本程序员的工作就是调整代码以检测/报告这些令牌的出现。

    这两种方法是相似的。首先,set 用于列出以cls[ 开头的已建立变量。第一个if 确保只处理数组名称cls,然后是重复(将prcoessed 设置为一个值并增加出现次数计数器)或者它是一个新值(当for...%%a 循环结束时, processed 仍然未定义)所以记录它。

    第二种方式更直接,使用count的值专门查询cls数组中的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-25
      • 1970-01-01
      • 2013-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多