Windows 批处理脚本中 FOR 命令中的令牌数限制

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/980791/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 12:37:31  来源:igfitidea点击:

Number of tokens limit in a FOR command in a Windows batch script

windowscommand-linescriptingbatch-file

提问by Paul

I was trying to process a text file in a Windows batch script and I ran into something that looks like a limitation to 31 tokens in a FOR loop. I isolated the issue in the code below:

我试图在 Windows 批处理脚本中处理一个文本文件,但我遇到了一些看起来像 FOR 循环中 31 个标记的限制。我在下面的代码中隔离了这个问题:

@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]
)

The output is:

输出是:

[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]

and I was expecting this:

我期待这个:

[31]
[32 33 34 35]

[32]
[33 34 35]

Hoping that I haven't been doing something wrong, I couldn't find this limitation documented in the help for the FOR command. I'm using Windows XP. Do you know any workaround for this, aside from chopping off parts of the data?

希望我没有做错什么,我在 FOR 命令的帮助中找不到这个限制。我使用的是 Windows XP。除了砍掉部分数据之外,您知道任何解决方法吗?

Thank you.

谢谢你。

回答by Paul

I came up with a solution. It's not elegant, but it solves my problem. When the commmand line interpreter cannot go further with the tokens, I pass the remaning of the data to a CALL :label command. Here is an example:

我想出了一个解决方案。这并不优雅,但它解决了我的问题。当命令行解释器无法进一步处理令牌时,我将数据的剩余部分传递给 CALL :label 命令。下面是一个例子:

@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

The output is:

输出是:

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

回答by Patrick Cuff

From for /?:

来自for /?

%i is explicitly declared in the for statement and the %j and %k are implicitly declared via the tokens= option. You can specify up to 26 tokens via the tokens= line, provided it does not cause an attempt to declare a variable higher than the letter 'z' or 'Z'. Remember, FOR variables are single-letter, case sensitive, global, and you can't have more than 52 total active at any one time.

%i 在 for 语句中显式声明,%j 和 %k 通过 tokens= 选项隐式声明。您可以通过 tokens= 行指定最多 26 个标记,前提是它不会导致尝试声明高于字母“z”或“Z”的变量。请记住,FOR 变量是单字母的、区分大小写的、全局的,并且在任何时候您的活动总数不能超过 52 个。

回答by Suvesh Pratapa

A token is the smallest unit of syntax that counts as one chunk. And a Batch command line in Windows 95/98/ME has a maximum limit of 64 tokens. Any more, and the command line will generate a Bad command or file nameerror.

标记是算作一个块的最小语法单位。Windows 95/98/ME 中的 Batch 命令行最大限制为 64 个令牌。再多,命令行就会产生Bad command or file name错误。

which is why you're probably limited to 31 within DATA.

这就是为什么您在 DATA 中可能仅限于 31。

回答by RobW

There is more than one way to loop through the DATA array:

遍历 DATA 数组的方法不止一种:

@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!

This is possible only because of the two character variables in the %DATA% array. As you will see, the limit is now 99 characters, rather than 31. When you get to the 100th and beyond, the number is truncated.

这是可能的,因为 %DATA% 数组中有两个字符变量。正如您将看到的,现在的限制是 99 个字符,而不是 31 个。当您达到第 100 个或更多时,该数字将被截断。

Rob

回答by FifthAxiom

I've created a typewriter function for batch (just for fun) and also encountered this limitation. Below a stripped-down version to show you how I fixed the problem. You can use up to 8,191 chars including space-separators when executed from the command line. When using a variable the maximum length is 32,767.

我为批处理创建了一个打字机功能(只是为了好玩),也遇到了这个限制。下面是一个精简版,向您展示我是如何解决这个问题的。从命令行执行时,您最多可以使用 8,191 个字符,包括空格分隔符。使用变量时,最大长度为 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

Execute: C:\Temp> typewriter "this is a test that works"

执行:C:\Temp> typewriter "this is a test that works"

Result:

结果:

this is a test that works

Changing the line <nul set /p "=!_WRD! "to echo !_WRD!will result in:

将行更改<nul set /p "=!_WRD! "echo !_WRD!将导致:

this
is
a
test
that
works

回答by Zimba

The FOR loop limitation is documented under header "Tokens" here:
https://ss64.com/nt/for_f.html

FOR 循环限制记录在此处的标题“令牌”下:https:
//ss64.com/nt/for_f.html

"A single FOR /F command can never parse more than 31 tokens, to use more requires a workaround with multiple FOR commands."

“单个 FOR /F 命令永远不能解析超过 31 个令牌,要使用更多令牌需要使用多个 FOR 命令的解决方法。”