Двойное расширение для индексации массива Windows Batch - PullRequest
0 голосов
/ 03 октября 2019

Внутри цикла for я пытаюсь получить доступ к элементу с индексом count в 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

Спасибо

Ответы [ 2 ]

1 голос
/ 03 октября 2019

Согласно сообщению Как интерпретатор сценариев Windows Command Interpreter (CMD.EXE) анализирует? (см. Этап 5), строка echo !!CLs[!count!]!! не может работать, потому что отверстие !! свернуто доодин !, затем !CLs[! расширяется до пустой строки (при условии, что такая переменная не определена), затем count возвращается буквально, затем !]! расширяется до пустой строки, а конечный ! равенуволен. Или, другими словами, отложенное расширение не может быть вложенным.

Вы можете использовать call, хотя для введения другой фазы синтаксического анализа, например:

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

Линия IF NOT %%I == CLs[!count!] ( ... ) неверна, вы также должны расширить правильное значение. Однако call if, к сожалению, не поможет, потому что if (например, for и rem) - это специальная команда, которая распознается синтаксическим анализатором раньше других, например call.

ToЧтобы обойти это, вы можете сохранить значение !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

Вы также можете взглянуть на сообщение Массивы, связанные списки и другие структуры данных в сценарии cmd.exe (пакетная обработка) о том, как обращаться с такими псевдо-массивами.

0 голосов
/ 03 октября 2019
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.

...