本帖最后由 CrLf 于 2014-4-29 00:54 编辑
一、十六进制转十进制- ::常见方案
- set hex=4F
- set /a num=0x%hex%
- echo 十六进制数 %hex% 的十进制数为 %num%
复制代码
- ::for /l 方案
- set hex=4F
- for /l %%a in (0x%hex% 1 0x%hex%) do echo 十六进制数 %hex% 的十进制数为 %%a
复制代码 二、useback,你可以安息了
注:useback 不是笔误,它和 usebackq 其实没有区别。
应对字符串本身带有引号的情况:- ::常见方案:
- set str="<test>"
- for /f useback %%a in ('%str%') do echo %%a
复制代码
- ::转义方案
- set str="<test>"
- for /f %%a in (^"%str%^") do echo %%a
复制代码 处理文件路径必须用引号的情况:- ::常见方案
- set "file=%programfiles%\(te)&(st).txt"
- for /f "useback delims=" %%a in ("%file%") do echo %%a
复制代码
- ::首引号方案(勘误方案,原理见 8 楼,感谢 7 楼的指正与启迪):
- set "file=%programfiles%\(te)&(st).txt"
- for /f "delims=" %%a in ("%file%
- ) do echo %%a
-
- rem 如果%file% 中不含特殊字符,可以写成一行为:
- rem for /f "delims=" %%a in (^"%file%) do echo %%a
复制代码
- ::上级路径方案
- set "file=%programfiles%\(te)&(st).txt"
- for /f "delims=" %%a in ("%file%\test"\..) do echo %%a
- rem 时灵时不灵,仅作参考...
复制代码 三、避免 for /f 从命令获取输入时,命令行参数首尾都有引号产生的错误处理字符串字符串本身带引号的情况:- ::错误模拟(假定 %programfiles% 含空格)
- for /f %%a in ('"%programfiles%\winrar\rar.exe" v "1.rar"') do echo %%a
- rem 错误产生原因见附文
复制代码
- ::解决方案
- for /f %%a in ('^;"%programfiles%\winrar\rar.exe" v "1.rar"') do echo %%a
复制代码 四、显示 test.txt 中含有“测试”的行- ::find 方案,直接,但是外部命令的效率欠佳
- find "测试"<test.txt
复制代码
- ::if+变量替换方案,效率和可控性好一些
- for /f "delims=" %%a in (test.txt) do (
- set str=%%a
- setlocal enabledelayedexpansion
- if "!str:测试=!" neq "!str!" echo !str!
- endlocal
- )
复制代码
- ::(感谢 powerbat 指出原纯 for 方案有盲点,现改为 for+if 方案)for+ if 方案,某些情况下是比较好的选择
- for /f "delims=" %%a in (test.txt) do (
- for /f "delims=试" %%b in ("[%%a]") do (
- for /f "tokens=2 delims=测" %%c in ("[%%b]") do if %%c==] echo %%a
- )
- )
复制代码 五、for 参数的妙用
以往我们认为 delims 的内容无法含双引号(由于 ^ 无法左右 for 内部的引号匹配,所以 "delims="^" 没有效果),以及 eol 不能为空("eol=" 会将双引号设为分隔符),但是换个角度来思考即可迎刃而解:for 参数真的需要双引号吗?- ::以双引号为分隔符
- for /f delims^=^" %%a in ("a"b"c") do echo 以 " 为分隔符的第一节为:%%a
复制代码 如此可以避免 for 解析参数时将 " 理解为参数分隔符,之所以要对 = 转义,是因为等号为 for 的默认分隔符,未通过转义符或双引号转义的等号在预处理时会被解释为空格
与 for 参数相关的讨论见:http://bbs.bathome.net/viewthread.php?tid=12500- ::设置 eol 为 null
- for /f "delims="eol^= %%a in (";") do echo 设置 eol 为 null 的结果为:%%a
复制代码 经过验证,在以 "delims="eol^= 为参数 for /f 参数时 0x1~0x79 均不是 eol 的值,含 \x0 的行会被自动忽略故无法验证
至于 0x80 之后的扩展字符因为通用性问题用到的机会很少(见注)故未测试,因此可以视为此处 eol 等于 null。
注:eol 存在只取宽字符的首字节的特性,所以“eol=测”("测"的gbk码为B2E2)等效于“eol=悴”("悴"的gbk码为B2E3),故不建议设置 eol 为宽字符
附文:
【三】的例子中无论 rar.exe 存不存在,都能触发错误解析,先看一下 for /? 系统帮助中的这一部分:
可以用 FOR /F 命令来分析命令的输出。方法是,将
括号之间的 filenameset 变成一个反括字符串。该字符串会
被当作命令行,传递到一个子 CMD.EXE,其输出会被捕获到
内存中,并被当作文件分析。如以下例子所示:
正如帮助中所述,因为 for /f 从命令获取输入时,实际上是执行了:
- cmd /c "%programfiles%\winrar\rar.exe" v "1.rar"
复制代码
而在 cmd /? 的系统帮助中又提到:
如果指定了 /C 或 /K,则会将该开关之后的
命令行的剩余部分作为一个命令行处理,其中,会使用下列逻辑
处理引号(")字符:
1. 如果符合下列所有条件,则会保留
命令行上的引号字符:
- 不带 /S 开关
- 正好两个引号字符
- 在两个引号字符之间无任何特殊字符,
特殊字符指下列字符: &<>()@^|
- 在两个引号字符之间至少有
一个空格字符
- 在两个引号字符之间的字符串是某个
可执行文件的名称。
2. 否则,老办法是看第一个字符
是否是引号字符,如果是,则去掉首字符并
删除命令行上最后一个引号,保留
最后一个引号之后的所有文本。 从这里可以看出实例代码中给出的参数在不满足条件1 的同时又满足了条件2,因此预处理时将消除最外层引号各一,所以 cmd.exe 子进程所执行的是 %programfiles%\winrar\rar.exe" v "1.rar,很明显的,这不是我们所希望的,当然破解方法也很简单,只要不让双引号位于参数头或尾,这个隐患即不攻自破,解决方案中的 ^; 即是在传递给子进程的参数前附加一个 ; 符号,子进程认为它是分隔符而忽略,同时也使得条件2 不被满足,同理,也可以使用 ^=、^, 或 @ 来代替 ^;,原理大同小异。 |