Antal tokens begrænses i en FOR-kommando i et Windows-batch script

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg forsøgte at behandle en tekstfil i et Windows-batch script, og jeg løb ind i noget, der ligner en begrænsning til 31 tokens i en FOR-loop. Jeg isolerede problemet i koden nedenfor:


@ECHO OFF
SET DATA=01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

FOR /F "tokens=31* delims= " \%\%i IN ("\%DATA\%") DO (
    ECHO [\%\%i]
    ECHO [\%\%j]
)
ECHO.
FOR /F "tokens=32* delims= " \%\%i IN ("\%DATA\%") DO (
    ECHO [\%\%i]
    ECHO [\%\%j]
)


Udgangen er:


[31]
[32 33 34 35]

[01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35]
[\%j]


og jeg forventer dette:


[31]
[32 33 34 35]

[32]
[33 34 35]


Håber jeg ikke har gjort noget forkert, kunne jeg ikke finde denne begrænsning dokumenteret i hjælpen til FOR-kommandoen. Jeg bruger Windows XP. Kender du nogen løsning til dette, bortset fra at hakke dele af dataene?


Tak skal du have.

Bedste reference


Jeg kom op med en løsning. Det er ikke elegant, men det løser mit problem.
Når kommandolinjestranden ikke kan gå videre med symbolerne, overfører jeg dataoverførslen til en CALL: label-kommando. Her er et eksempel:


@ECHO OFF

SET DATA=01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

FOR /F "tokens=1,31* delims= " \%\%i IN ("\%DATA\%") DO (
    ECHO  1st token: \%\%i
    ECHO 31th token: \%\%j
    CALL :processdatatokens32-62 \%\%k
)

:processdatatokens32-62
SET DATA=\%*
FOR /F "tokens=1,31* delims= " \%\%i IN ("\%DATA\%") DO (
    ECHO 32nd token: \%\%i
    ECHO 62th token: \%\%j
    CALL :processdatatokens63-83 \%\%k
)
GOTO :EOF

:processdatatokens63-83
SET DATA=\%*
FOR /F "tokens=1,31* delims= " \%\%i IN ("\%DATA\%") DO (
    ECHO 63th token: \%\%i
    ECHO 93th token: \%\%j
)
GOTO :EOF


Udgangen er:


 1st token: 01
31th token: 31
32nd token: 32
62th token: 62
63th token: 63
93th token: 93

Andre referencer 1


Fra for /?:



  \% jeg er udtrykkeligt erklæret i for
  erklæring og\% j og\% k er
  implicit erklæret via tokens =
  mulighed. Du kan angive op til 26
  tokens via tokens=linje, forudsat
  det forårsager ikke et forsøg på at
  erklære en variabel højere end
  bogstavet 'z' eller 'Z'. Husk, FOR
  variabler er single-letter, sag
  følsom, global, og du kan ikke have
  mere end 52 totalt aktive på nogen
  tid.


Andre referencer 2


Et token er den mindste enhed af syntaks, der tæller som en klump. Og en kommandolinje i Batch i Windows 95/98/ME har en maksimal grænse på 64 tokens. Endnu mere, og kommandolinjen genererer en Bad command or file name fejl.


Derfor er du sandsynligvis begrænset til 31 inden for DATA.

Andre referencer 3


Der er mere end en måde at løbe gennem DATA array:


@ECHO OFF
setlocal ENABLEDELAYEDEXPANSION
SET DATA=01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101

for /l \%\%a in (0,3,150) do @echo \%\%a data: !data:~\%\%a,2!


Dette er kun muligt på grund af de to tegnvariabler i\% DATA\% array. Som du vil se, er grænsen nu 99 tegn, snarere end 31. Når du kommer til 100 og derover, er nummeret afkortet.


Røve

Andre referencer 4


Jeg har lavet en skrivemaskinefunktion til batch (bare for sjov) og også oplevet denne begrænsning. Nedenfor er en udrullet version, der viser dig, hvordan jeg løste problemet. Du kan bruge op til 8.191 tegn inklusive rumseparatorer, når de udføres fra kommandolinje. Ved brug af en variabel er den maksimale længde 32.767.


@echo off
::#############################################################################
 :\_typeWriter <stringVariable> <skipLinefeed>
::#############################################################################
::
:: Copyleft Denny Lenselink 2018
::

\%= Set local environment =\%
( call ) & 2>nul setlocal EnableDelayedExpansion || exit /b 99

:: Set vars
set "\_CNT=0" && set "\_LEN=0" && set "\_STR= \%~1" && set "\_TOT=0"

:\_typeWriter\_Loop
set /a "\_CNT+=1"

:: 31 tokens limit fix. Cut the used part of the string and set counter to 1
if !\_CNT! equ 32 ( set "\_CNT=1" && set "\_STR=!\_STR:~\%\_TOT\%!" && set "\_TOT=0" )

:: Go through string (seeking words)
for /f "tokens=\%\_CNT\% delims= " \%\%* in ( "\%\_STR\%" ) do (

    :: Set word var
    set "\_WRD=#\%\%*"

    :: Calculate word length
    for /l \%\%I in ( 12, -1, 0 ) do (

        set /a "\_LEN|=1<<\%\%I"

        for \%\%J in ( !\_LEN! ) do ( if "!\_WRD:~\%\%J,1!"=="" set /a "\_LEN&=~1<<\%\%I" )
    )

    :: Strip first char (used before to calculate correct word length)
    set "\_WRD=!\_WRD:~1!"

    :: Count chars including spaces
    set /a "\_TOT=!\_TOT!+!\_LEN!+1"

    :: Type word or use echo
    <nul set /p "=!\_WRD! "

    :: Do a loop
    goto \_typeWriter\_Loop
)

:: No linefeed when specified
if "\%~2"=="" echo.

endlocal
exit /b


Udfør:
C: \ Temp> typewriter "this is a test that works"


Resultat:


this is a test that works


Ændring af linjen <nul set /p "=!\_WRD! " til echo !\_WRD! vil resultere i:


this
is
a
test
that
works