|
转自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 编辑 ] |
|