为什么FOR / F为其余标记中的重复数字设置空值?

时间:2014-09-20 15:11:47

标签: batch-file

不确定问题是否足够清楚,以下是一个例子:

:::this prints - 1:[i] 2:[] 3:[] 4:[] 5:[] 6:[] 7:[]
for /f "tokens=1,1,1,1,1,1,1" %%a in ("i ii iii iv v vi vii") do (
    @echo 1:[%%a] 2:[%%b] 3:[%%c] 4:[%%d] 5:[%%e] 6:[%%f] 7:[%%g]
)

:::this prints - 1:[i] 2:[ii] 3:[iii] 4:[iv] 5:[] 6:[] 7:[%g]
for /f "tokens=2,3,1-4" %%a in ("i ii iii iv v vi vii") do (
    @echo 1:[%%a] 2:[%%b] 3:[%%c] 4:[%%d] 5:[%%e] 6:[%%f] 7:[%%g]
)

:::this prints - 1:[i] 2:[ii] 3:[iii] 4:[] 5:[] 6:[] 7:[%g]
for /f "tokens=1-3,1-3," %%a in ("i ii iii iv v vi vii") do (
    @echo 1:[%%a] 2:[%%b] 3:[%%c] 4:[%%d] 5:[%%e] 6:[%%f] 7:[%%g]
)

简而言之,如果令牌列表中有重复的数字(如果它们在n-m范围内或者用逗号逐个设置则无关紧要)相同的数字左访问令牌有空值。

没有记录这种行为(或者至少我没有找到这样的事情)。这里有关于令牌的FOR帮助:

tokens=x,y,m-n  - specifies which tokens from each line are to
                  be passed to the for body for each iteration.
                  This will cause additional variable names to
                  be allocated.  The m-n form is a range,
                  specifying the mth through the nth tokens.  If
                  the last character in the tokens= string is an
                  asterisk, then an additional variable is
                  allocated and receives the remaining text on
                  the line after the last token parsed.

这是Win8x64上的睾丸,所以我甚至不确定这会在所有Windows机器上发生。

编辑:尽管可访问的令牌限制为31,但我可以创建更多空标记:

setlocal disableDelayedExpansion
for /f "tokens=1-31,1-31,1-31" %%! in (
"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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 "
) do (
 echo 1:[%%!-!]  30:[%%?-?] 31:[%%@-@] 32:[%%A-A] 33:[%%B-B] 34:[%%C-C] 35:[%%D-D] 36:[%%E-E] 37:[%%F-F] 38:[%%G-G] 90:[%%{-{] 
)

修改。空标记的最大值为250(不确定扩展的ascii字符将如何显示在0x02和0xFB之间):

@echo off
for /f "tokens=1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31" %% in (
"1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1") do (
    echo 0x02-%%- 0x07-%%- 0xFE-%%ю-  0xFB-%%ы- 0xFA-%%ъ- 
)

2 个答案:

答案 0 :(得分:4)

虽然我不清楚为什么for命令的行为,但有一些简单的规则与for行为相匹配。在这里,我们只讨论token条款。其他日期delimseolskipusebackq

第1步 - 找到了令牌子句。解析该子句,并且对于请求的每个范围(仅一个,起始端,*),确定它是否有效。如果它不是有效请求(不在1-31范围内或不在*范围内),则被丢弃,但如果它是有效请求,则对于请求的每个元素,分配“变量”(可能是表)稍后保存为此令牌检索的数据。同时,定义“set”(可能是位图掩码),设置将检索令牌号x(用于标识tokens子句中的令牌的数量)。可以多次请求相同的令牌,但在“set”(或位掩码,...)中,唯一的效果是再次标记将检索令牌x。

现在“set”包含所请求的有效(1-31,*)令牌的位置。

在解析器结束处理for配置之后,输入文件被重新加入内存,或者执行命令将其所有输出检索到内存中,或者将文字字符串声明为输入缓冲区。 / p>

第2步 - 准备行解析。保存令牌数据的表初始化为空白,并且指针设置为表中的第一个位置(第一个令牌)。如果该行未被skipeol丢弃或因为它为空,则标记生成器将扫描输入缓冲区中的标记,否则,搜索行的末尾并重复步骤2以获取新标记发现了一条线。

第3步 - 解析输入缓冲区。在到达某一行的末尾之前,对于在该行中找到的每个令牌,如果在范围(1-31或*令牌中),则在“set”中检查以确定是否已请求或not(如果此令牌号位于集合中或者正在处理*令牌)。如果已经请求,其数据是否包含在“表格”中?在表指针指示的位置,指针递增,令牌器继续重复步骤3,直到到达行尾。

第4步 - 已达到该行的结尾。如果已检索到任何令牌,或者请求的唯一令牌是*(test for /f "tokens=*" %a in (" ") do echo %a),请执行do子句中的代码。

步骤5 - 如果for的执行尚未取消且尚未到达缓冲区的末尾,则需要处理更多行,返回步骤2。

这组步骤重现了问题中所有观察到的行为,但不能证明这是for命令的编码方式。

现在,让我们根据问题中的代码进行检查

:::this prints - 1:[i] 2:[] 3:[] 4:[] 5:[] 6:[] 7:[]
for /f "tokens=1,1,1,1,1,1,1" %%a in ("i ii iii iv v vi vii") do (
    @echo 1:[%%a] 2:[%%b] 3:[%%c] 4:[%%d] 5:[%%e] 6:[%%f] 7:[%%g]
)

7个请求令牌,因此表中的7个位置将传递给do代码,但唯一与“set”匹配的令牌是数字1

:::this prints - 1:[i] 2:[ii] 3:[iii] 4:[iv] 5:[] 6:[] 7:[%g]
for /f "tokens=2,3,1-4" %%a in ("i ii iii iv v vi vii") do (
    @echo 1:[%%a] 2:[%%b] 3:[%%c] 4:[%%d] 5:[%%e] 6:[%%f] 7:[%%g]
)
6请求令牌,6个位置在令牌表中,而“设置”只匹配1,2,3,4

:::this prints - 1:[i] 2:[ii] 3:[iii] 4:[] 5:[] 6:[] 7:[%g]
for /f "tokens=1-3,1-3," %%a in ("i ii iii iv v vi vii") do (
    @echo 1:[%%a] 2:[%%b] 3:[%%c] 4:[%%d] 5:[%%e] 6:[%%f] 7:[%%g]
)
6请求令牌,令牌表中的6个位置,而“设置”仅匹配1,2,3

setlocal disableDelayedExpansion
for /f "tokens=1-31,1-31,1-31" %%! in (
"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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 "
) do (
 echo 1:[%%!-!]  30:[%%?-?] 31:[%%@-@] 32:[%%A-A] 33:[%%B-B] 34:[%%C-C] 35:[%%D-D] 36:[%%E-E] 37:[%%F-F] 38:[%%G-G] 90:[%%{-{] 
)
93请求令牌,在令牌表中分配93个位置,“设置”只匹配元素1-31

已修改更多案例已添加到问题

  

空标记的最大值为250

@echo off
for /f "tokens=1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31,1-31" %% in (
"1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1") do (
    echo 0x02-%%- 0x07-%%- 0xFE-%%ю-  0xFB-%%ы- 0xFA-%%ъ- 
)

不,你可以尽可能多地请求令牌。我测试了1625 1-30和一个aditional 31(以确保解析器继续工作),并且处理没有问题。可能限制是行长。您可以请求最多50530(aprox)令牌(重复1-31,......以达到行限制),但您只能获得31个第一个令牌的有效数据和其他元素的空白数据。存储表,必须使用for可替换参数中的单个字符检索元素。使用%%^A(0x01, Alt-001 )作为for可替换参数,您最多可以请求%%ÿ(0xFF, Alt-255 < / KBD>)

答案 1 :(得分:1)

我也没有解释,但我确实有其他影响。

仍然接受@echo off for /f "tokens=1,1,2*" %%a in ("1 2 3 4") do ( echo a=%%a echo b=%%b echo c=%%c echo d=%%d echo e=%%e ) “令牌”,但如果至少有一个重复的令牌请求,它将始终为空(功能失调)。

a=1
b=2
c=
d=
e=%e

- 输出 -

QHeaderView::section {                          
    color: black;                               
    padding: 2px;                               
    height:20px;                                
    border: 0px solid #567dbc;                  
    border-left:0px;                            
    border-right:0px;                           
    background: #f9f9f9;                        
}