|  | 
 
| 转自CN-DOS论坛 
 刚才看到讨论for的tokens
 虽然有一两篇精贴
 但被众多口水淹没
 让人很没有讨论的心情
 索性换到正式场合另开新帖讨论
 ----------------------------------------
 上文几位老兄讲得大致不错
 只是在某些细节上还点得不够到位
 tokens中有几个重要的细节也是缺陷
 是所有喜欢玩脚本的老兄都应该注意的
 
 为讨论方便首先建立一个测试文件
 echo 1 2 3 4 5 6 7 8 9 10 11 12 > test
 
 另外以下所有代码都是在命令行中测试
 在bat中测试请自行修改
 --------------------------------------------------------------------------------
 细节或缺陷之一:order
 
 猜猜下句的执行结果
 for /f "tokens=9,8,7" %i in (test) do echo %i-%j-%k
 是9-8-7吗?
 错!是7-8-9
 也就是说令牌是按照它在字符串中的排序值赋给变量的
 跟代码中的书写顺序毫不相关
 所以不管你怎么设置令牌顺序
 它总是按照从小到大的顺序赋值给迭代变量
 也就是说你可以随意变换tokens的顺序
 而不必担心代码执行结果会有什么变化
 只有一个例外(下面会有提到)
 
 这对你是一个好消息吗?
 至少对于我是一个坏消息!
 
 因为某些时候我就想获得9-8-7的顺序
 但我必须自己通过对变量进行重组才能得到这样的顺序
 --------------------------------------------------------------------------------
 细节或缺陷之二:*
 
 其意义不言自明
 获取剩余的所有令牌到一个变量
 
 注意它必须位于所有令牌的尾部
 否则会报错
 这就是细节之一提到的唯一的例外
 它的顺序不能随意变化
 
 *的另外一个特性就是它隐含一个,
 也就是说*可以不像其它令牌那样必须前缀一个逗号分隔符
 
 所以以下两句的执行结果都是一样的
 for /f "tokens=1,2*" %i in (test) do echo %i-%j-%k
 for /f "tokens=1,2,*" %i in (test) do echo %i-%j-%k
 
 因为在cmd的令牌串中间没有空令牌的存在
 
 --------------------------------------------------------------------------------
 细节或缺陷之三:m-n
 
 最初写cmd脚本总以为m-n获取第m到n个令牌到一个变量
 后来碰壁了才知道根本不是这么回事
 
 再猜猜这句的结果
 for /f "tokens=1-7,8,9" %i in (test) do echo %i-%j-%k
 
 它的结果是是1-2-3,而不是1 2 3 4 5 6 7-8-9
 也就是说1-7是指将第1-7个令牌分别取到了7个变量中
 其中%i %j %k分别接收到了第1,2,3个令牌
 第4-9个令牌因为没有变量接收所以被丢弃了
 
 这个细节可以说我很不欣赏
 因为逐个获取多个令牌到多个变量是完全可以通过笨办法来实现的
 而完整获取多个令牌到一个变量是没有现成的好办法的
 比如我想获取3 4 5 6 7到一个变量中该怎么办?
 
 Q 可以用多个单令牌变量拼凑一个多令牌变量吗?
 A 请考虑考虑delims的多样性
 
 Q 可以用不带分割符的令牌符号(如1,2,34567,8,9)吗?
 A cmd会执着的将34567认做一个超远的令牌(当然找不到)
 
 Q 可以用*解决多令牌变量问题吗
 A 那会多取8 9 10 11 12等令牌到变量
 
 所以之后我见到代码里有tokens=1,2,3,4,5,6,7,8等类似代码
 总是忍不住吁叹——
 真是身在福中不知福啊!
 --------------------------------------------------------------------------------
 细节或缺陷之四:shift
 
 在我们遇到一个超长令牌串时
 会发现使用完26个字母也无法取到足够的令牌
 
 或者遇到一个不知或不等长度的令牌串时
 我们根本无法获知第n个令牌究竟是空还是不空
 
 这是我就十分盼望有一个类似shift的处理令牌串移位的指令
 能够让我对这个令牌串得心应手的操作
 当然在ms没有满足我的要求之前
 只好自立更生艰苦创业了
 
 “没有枪没有炮敌人给我们造——”
 
 这个方法也已经有很多人再用了
 for /f "tokens=*" %i in (test) call script.cmd %i
 当然script.cmd的脚本名更多时候会被改为一个批处理自身的标签
 
 但如果这中间的delims竟然不是空格、跳格、等号、分号
 那就够让人头疼的了!
 -----------------------------------------------
 for /f 的options有固定的优先顺序
 当在tokens的值中出现了*,那么对应的delims值就被忽略了
 原来
 for /f "tokens=1* delims=*" %a in (abcd*efg*hijk*lmn) do echo %a %b
 
 这样的命令取得的值不是
 abcd efg hijk lmn而是abcd efg*hijk*lmn
 -------------------------------------------------
 
 for可以取到超过26个变量的值,初步猜想是根据ASCII的大小顺序来取的。
 test.txt
 上面的文本是用逗号分隔,而且就一行。复制代码a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33,a34,a35,a36,a37,a38,a39,a40 
结果是:复制代码for /f "delims=, tokens=1-31" %A in (test.txt) do @echo:第1个变量:%A,第27个变量:%[,第29个变量:%],第31个变量:%_
第1个变量:a1,第27个变量:a27,第29个变量:a29,第31个变量:a31
 而且还发现,tokens的个数只能取到31个,超过31个执行就没结果了。
 比如:
 这个执行没有任何结果。复制代码for /f "delims=, tokens=1-32" %A in (test.txt) do @echo:第1个变量:%A,第27个变量:%[,第29个变量:%],第31个变量:%_
当然,for初始变量的可以指定为非字母的字符。
 比如:
 结果是:复制代码for /f "delims=, tokens=1-10" %! in (test.txt) do @echo:%!\%"\%#\%$\%&
a1\a2\a3\a4\a6
 对于特殊字符命名的变量还是无法处理,比如本例中的%%(%的ASCII位于$和&之间)这个就无法取到。
 ------------------------------------------------------
 迭代变量可以取更多ASCII字符这很早就有谈论了
 只要选对好的起始点大约可以取将近90个变量
 
 而且只要想到cmd乃至windows内部是完全unicode的
 那么双字节字符作变量也应该不算稀奇了
 for /f "tokens=1-7" %⒈ in (test) do echo %⒉ %⒊ %⒋
 
 这样能设置的迭代变量就数量上而言足够使用了
 
 ---------------------------------------------------------
 
 [ 本帖最后由 2011czmxbb52 于 2012-3-13 14:19 编辑 ]
 | 
 |