标题: [原创] 趣味统计:批处理脚本中的数字 [打印本页]
作者: CrLf 时间: 2012-3-21 17:20 标题: 趣味统计:批处理脚本中的数字
本帖最后由 CrLf 于 2016-1-6 17:31 编辑
提示:注意描述语句中“字节”、“字符”的区别,字符根据代码页的不同,在 ansi 编码里可能为 1~2 字节长度。
【0】- set /a 里直接通过变量名由 set 解释变量时,空变量名或变量值不为合法数字的变量都被理解为 0
- for /l 会将参数中不为有效数字的项和缺失的项理解为 0,典型例子为 for /l %%a in () do echo 无限循环
复制代码
【1】- 0D 0A 这一对回车换行符在预处理时将被理解为 1 个 0A 字符
- for /f 中的 skip 至少等于 1
- pause 可接受任意 1 个字符为输入
复制代码
【4】- 许多命令默认只判断后缀名的前 4 字节(含 . 在内),所以使用 dir、type、findstr 等命令对 *.txt 通配时无法区分 a.txt 和 a.txtt,当通配条件不使用 * 或后缀名超过 4 字节时将自动改用完整匹配
复制代码
【8】- 短名最长 8 字节
- 制表符(tab)宽度为 8 字节
- more 会将 tab 转化为等宽度的空格(默认 8 个字节)
复制代码
【10】- cmd 最多支持同时直接操作 10 个句柄:句柄0 标准输入,句柄1 标准输出(约定俗成),句柄2 标准错误(亦然),句柄3~9 由命令自定义,共 10 个句柄,但句柄备份证明句柄9 之后至少还存在一个无法直接操作的隐藏句柄10
复制代码
【32】- setlocal 最多嵌套 32 层(本质是最多允许用 setlocal 创建 32 张临时变量表),call 可以在调用过程中将层数暂时归零,等子过程退出后恢复
- for /f 的 tokens 设置项最多支持 32 节,但是无论是否声明 * 都必须为其保留一个位置,所以若要用全 32 节,必须声明为 tokens=1-31*(无法直接声明超过 31 的节)
- cmd 计算时以 long int 的数据类型进行操作,其中的数字由 32 位组成
复制代码
【512】复制代码
【1024】- set /p 最多容许 1024 个字节长度,但若第 1023、1024 字节处所取得的两字节不是一个完整的宽字符时,最多容许 1023 字节
复制代码
【4096】- sort 命令的 /rec 开关默认值为 4096,即默认支持对短于 4096 字符的行进行排序(此设置可更改)
复制代码
【8153】- 64 位 Windows7 中,cmd 的单条命令行长度上限为 8153 字符
- 有趣的是,在 xp 的 cmd 中,该上限为 8154 字符
复制代码
【8192】- cmd 从脚本中一次读入 8192 字符
- 变量长度最长为 8192 字符,包括变量名、等号和内存中的变量分隔符 00
- 若因内存泄露导致变量末尾的 00 丢失,使用 %var% 或 !var! 引用变量时只会读取 8192 字符长度
复制代码
【32767】复制代码
【65535】- cmd 所能使用的内存空间上限为 65536K,但是每次 call 都能额外领取空间额度。
- sort 支持的行长度上限为 65535 字符
- more 执行时一次最多操作 65535 行
- debug 支持的段空间为 65535 字节(因为它是 16 位的 com),所以仅支持小于 64K 的文件
复制代码
【-2147483648 与 2147483647】- cmd 中数值的上下限,其实就是 long int 支持的计算范围
复制代码
作者: find 时间: 2012-3-21 20:22
版主V5
作者: ivor 时间: 2012-3-22 03:07
文章写的不错,学习一下
作者: qzwqzw 时间: 2012-3-22 22:06
ms-its:C:\WINDOWS\Help\ntcmds.chm::/goto.htm
这个微软文档的描述有些过时了
这是旧DOS和Win9x时代的Label特性
在Winnt下已经不限制字节数了
当然因为cmd每次只读取512个“字符”
所以可能会无法无法处理超过512字符的长标签
尽管这个临时缓冲区可能有2048个“字符”
作者: qzwqzw 时间: 2012-3-22 22:46
本帖最后由 qzwqzw 于 2012-3-22 22:47 编辑
cmd 最多支持同时直接操作 10 个句柄:句柄0 默认输出,句柄1 正确输入(约定俗成),句柄2 错误输出(亦然),句柄3~9 由命令自定义,共 10 个句柄,但句柄备份证明句柄9 之后至少还存在一个无法直接操作的隐藏句柄10
句柄0 1 2 的描述都有问题
句柄0 stdin 标准输入,只可读
句柄1 stdout 标准输出,只可写
句柄2 stderr 标准错误,只可写
在DOS虚拟机VDM中
句柄3 stdaux 标准串口
句柄4 stdprn 标准并口
其他的句柄未初始化
句柄的个数确实不止10个
通常每个进程可以同时最多操作20个句柄
某些多线程环境下会最多同时操作40个句柄
但是cmd只给了我们前10/11个句柄的操作接口
cmd在句柄备份时的策略
是确定要备份的目标句柄是否被“污染”
如果被污染则选择下一个新句柄判断
这个判断是基于一个3X32位的flag字
靠设置和获取对应号位上的0/1来确定
作者: qzwqzw 时间: 2012-3-22 23:03
许多命令只判断后缀名的前 4 位(含 . 在内),所以 dir 无法区分 a.txt 和 a.txtt
立论有问题
dir是存在dir *.txt时将a.txtt也列出a.txtt的现象
但是dir *.txtt可以只列出a.txtt而没有a.txt
不能据此得出命令只判断后缀名的前 4 位
作者: wankoilz 时间: 2012-3-22 23:05
很有创意的总结!
作者: CrLf 时间: 2012-3-22 23:24
回复 4# qzwqzw
感谢指正,原内容已按提示修正
作者: qzwqzw 时间: 2012-3-23 13:47
看你【4】段基本保持原貌
不止是否还有其他例证?
作者: CrLf 时间: 2012-3-23 15:59
回复 9# qzwqzw
感觉似乎是通病,测试了几个常用的支持文件通配符的命令(包括已测试的外部命令)都存在这个问题
修改了一点,麻烦再把关下。
作者: Demon 时间: 2012-8-16 23:13
【8192】- cmd 从脚本中一次读入 8192 字符
- 变量长度最长为 8192 字符,包括变量名、等号和内存中的变量分隔符 00
- 若因内存泄露导致变量末尾的 00 丢失,使用 %var% 或 !var! 引用变量时只会读取 8192 字符长度
复制代码
缓冲区的大小为8192字节,一次读入的是8191字节而不是8192字符,最后一个字节用来保存C语言字符串结束符NULL。
所谓内存泄露是指动态分配的内存没有被合理的回收而导致可用内存的减少,不知道这跟变量末尾的 00 丢失有什么关系,以及在什么情况下变量末尾的 00 会丢失?
作者: CrLf 时间: 2012-8-17 02:50
本帖最后由 CrLf 于 2012-8-17 04:45 编辑
回复 11# Demon
从测试的表象来看确实是字符:- Const num = 8192
- Const text = "测"
- '比较奇特的是,在 xp 环境下测试时,
- '如果 text="t",则 cmd 遇到超过 8192 字符长度的行将无提示退出
- '如果 text="测",则 cmd 会对字符串进行截断,且不会因为超长而退出
- '没有细究宽字符与单字节字符共存的复杂关系下有何异同
- 'win7 不存在出错退出的现象,且上次曾和兄台讨论过得知 win7 下的 cmd 会分段读取超长行的内容(不好意思,忘记是哪个帖了,链接就不贴了)
-
- Set fso = CreateObject("Scripting.FileSystemObject")
- str = "echo " & String(num,text)
-
- With fso.CreateTextFile("test.bat",True)
- .Write "@echo off" & vbCrLf
- .Write str
- .Close
- End With
-
- Set ws = CreateObject("Wscript.Shell")
-
- out = ws.exec("cmd /c test.bat").stdout.readall
-
- MsgBox "strlen=" & Len(str) & vbCrLf &_
- "outlen=" & Len(out) & vbCrLf &_
- out
复制代码
至于 cmd 一行具体读入的数量...我是听另一位大牛说的,这是他 hook 出来的数据,从纯批的测试结果看来也是如此,如果将那个被转为 null 的换行符计算在内刚好 8192,不算的话则是 8191
变量末尾的 00 丢失现象:http://bbs.bathome.net/redirect. ... 3&fromuid=30406
最早提及这个现象的帖子不知道在何处,我也只懂得用 debug 看内存来旁敲侧击猜测成因,不知其本质何在。至于内存泄露一说,时隔数月已经印象模糊了,只记得那时在讨论 for /f 的 bug,不记得写此贴时是否是在援引他人观点,也可能是本人当时思维混乱了吧...
当时听 qzw 说到内存泄露的帖子是:
http://bbs.bathome.net/viewthread.php?tid=15748
后来一搜发现早有类似的先例(题外话:这 tid 果然早啊...):
http://bbs.bathome.net/viewthread.php?tid=3614
其实那个帖子肯定也不是 first,印象中听很多前辈说 for /f usebackq 是经常出这种问题的,不过我是没碰到过的,也许因为他们是 xp 系统?
作者: Demon 时间: 2012-8-17 14:13
本帖最后由 Demon 于 2012-8-17 14:14 编辑
看来又是系统之家的差异,Windows 7是一次读取8191(0x1FFF)个字节
[attach]5596[/attach]
而XP是一次读取8192(0x2000)个字节
[attach]5595[/attach]
你给出的例子只是表面现象,
"echo " & String(8192,"t"),读取8192个字节转成Unicode后是8192个字符,XP下大于等于8192个字符就会报错“输入行太长。”
"echo " & String(8192,"测"),由于第8192个字节(0xB2)是GBK编码的高位字节(LeadChar),这时CMD会再多读一个字节,也就是一共会读取8193个字节(AnsiBuf缓冲区其实不止8192个字节,之前弄错了),
转成Unicode之后是4099个字符(5 + (8193 - 5) / 2 = 4099),小于8192,所以不会报错。
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |