0

Inside the for loop I'm trying to access the element at index count in CLs (this line of code: echo !!CLs[!count!]!!) , but I'm not sure how to do this. I don't really understand how expansion works in this case, so what you see below it me trying something out of no where.

@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

Thanks

Linkxgl
  • 161
  • 4
  • 14
  • 1
    Have you tried `Call Echo %%CLs[!count!]%%`? – Compo Oct 02 '19 at 21:50
  • This would appear to be an X-Y problem Please post the *actual* problem you are attempting to solve. Are you attempting to find `%%I` in an established array of `CLs` (not the best name in batch since `cls` is a keyword) or add unique enties to the array `CLs` or what? – Magoo Oct 03 '19 at 01:15
  • @Magoo I'm trying to make an array of just specific unique tokens from the command output. Does that help? – Linkxgl Oct 03 '19 at 15:07

2 Answers2

2

According to the post How does the Windows Command Interpreter (CMD.EXE) parse scripts? (see phase 5), the line echo !!CLs[!count!]!! cannot work, because the opening !! are collapsed to a single !, then !CLs[! is expanded to an empty string (assuming such variable is not defined), then count is returned literally, then !]! is expanded to an empty string and the final ! is dismissed. Or in other words, delayed expansion cannot be nested.

You can use call though to introduce another parsing phase, like this:

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

The line IF NOT %%I == CLs[!count!] ( ... ) is wrong, you must expand the right value too. However, call if will not help unfortunately, because if (like for and rem) is a special command that is recognised by the parser earlier than others, like call.

To work around that you can store the value of !count! in a for meta-variable, like %%J, for instance, to introduce another parsing phase, and use !CLs[%%J]! then, like this:

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"
        )
    )
)

Another yet slower possibility is to put the relevant code into a sub-routine:

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

You may also take a look at the post Arrays, linked lists and other data structures in cmd.exe (batch) script about how to deal with such pseudo-arrays.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
0
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

I used a file named q58209698.txt containing some dummy data for my testing and chose to use the entire data line, having no suitable files where token 5 existed.

Note that as a bonus, I've added clscnt - an array of occurence-counts.

Shown: two separate ways of achieving the aim of finding/counting the unique tokens. Naturally, if the cls array is pre-loaded with the required tokens, then it's basic-programmer's-play to adjust the code to detect/report occurrences of those tokens.

The two methods are similar. In the first, set is used to list the established variables starting cls[. The first if ensures processing only the array-name cls, then either it's a repeat (set prcoessed to a value and increment the occurrences-counter) or it's a new value (when the for...%%a loop ends, processed is still undefined) so record it.

The second way is more direct, using the value of count to specifically interrogate the values in the cls array.

Magoo
  • 77,302
  • 8
  • 62
  • 84