[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[其他] echo 最佳用法考

本帖最后由 CrLf 于 2012-8-3 19:12 编辑

运行测试代码(需要 ascmap.cmd 函数文件:http://bbs.bathome.net/thread-12347-1-1.html):
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. call ascmap $
  4. cd .>enable.txt
  5. for /l %%a in (0x20 1 0x7f) do (
  6. echo "!$:~%%a,1!"
  7. %comspec% /v:off /c "echo!$:~%%a,1! test" 2>nul|findstr " test" &&echo %%a=%%a>>enable.txt
  8. )
  9. pause
复制代码
测得 echo 可用参数分隔符如下(格式:"[字符]"=[ASC]):
  1. " "=32
  2. "("=40
  3. "+"=43
  4. ","=44
  5. "."=46
  6. "/"=47
  7. ":"=58
  8. ";"=59
  9. "="=61
  10. "["=91
  11. "\"=92
  12. "]"=93
复制代码
以下为一些测试结论:
1、echo 后跟空格的用法通用性最差,不兼容空行或仅含空格的行、不能直接显示 /?、on 和 off:
  1. echo
  2. echo /?
  3. echo on
  4. echo off
复制代码
2、而 ; , = 同属于 cmd 中的默认分隔符,虽然是对空格的改进,却仍无法显示 /?:
  1. echo;/?
  2. echo,/?
  3. echo=/?
复制代码
3、echo 后跟 .、:、\、+、[ 或 ] 时,能将参数理解为消息,但是会触发对文件的搜索,所以效率会降低
(参考:http://bbs.bathome.net/redirect. ... 2&fromuid=30406
与:http://bbs.bathome.net/redirect.php?tid=18352),并有可能打开路径相吻合的文件
  1. @echo off&setlocal enabledelayedexpansion
  2. for %%a in (";" . : \) do (
  3. (set timea=!time!
  4. for /l %%b in (1 1 10000) do echo%%~a
  5. call :时差 !timea! !time!)>nul
  6. echo 运行 10000 次 echo%%~a 的用时为: !时差!
  7. )
  8. pause
  9. :时差
  10. for /f "tokens=1-8 delims=:. " %%a in ("%*") do (
  11. set /a "时差=(((%%e-%%a)*60+1%%f-1%%b)*60+1%%g-1%%c)*100+1%%h-1%%d"
  12. )
复制代码
4、如此排除,就只剩下了 (,经测试,其各方面兼容性均达标,唯一的遗憾大概就是会影响编辑器中的括号匹配:
  1. setlocal enabledelayedexpansion
  2. echo(
  3. echo(/?
  4. echo(on
  5. echo(off
  6. echo(!tmp:\=!
复制代码
结论:以后还是用 echo( 好了,丑是丑了点,胜在通用性。


附原第 4 点:
------------------------------------------------------------------------------------------------------------------
4、echo 后跟 .、:、\、+、[ 或 ] 时会十分离奇地在特定情况下(比如参数中无空格)禁用对延迟变量中的变量替换进行解释:
  1. setlocal enabledelayedexpansion
  2. echo.!tmp:\=!
  3. echo:!tmp:\=!
  4. echo\!tmp:\=!
  5. echo+!tmp:\=!
  6. echo[!tmp:\=!
  7. echo]!tmp:\=!
复制代码
------------------------------------------------------------------------------------------------------------------
本贴 3楼 demon 猜测这其实是命令被优先理解为路径导致的,经证实确实如此,解决方法是转义 ! 号对中的默认分隔符:
  1. echo\!tmp:\^=!
复制代码
与第3点本质上有所重复,故从正文中移除。

本帖最后由 CrLf 于 2012-8-3 17:32 编辑

回复 3# Demon


    老兄对第 4 点的解释确实很有道理,恍然大悟,实际原因大约就在于此,这和 echo.bat 的原因一致:
  1. echo.bat
  2. ::先对文件名进行匹配,找不到时再以 echo 命令解读
  3. echo pause>echo.bat
  4. echo.bat
  5. ::由于找到了相应的文件,所以执行的是 echo.bat 而非 echo 命令
  6. echo test
  7. ::虽然 bat 可以只靠文件名来调用,但是内部命令例外
复制代码
括号的错误匹配一向是发生在 ) 的多余和缺失上,与 ( 无关,所以括号对中的 echo((1+2)*3=9 只要改成 echo((1+2^)*3=9 就能正确运行了,所以并非 "echo( 通用性最强" 的反例。

另外,不知为何在同样需要搜索文件的前提下,+、[、] 的效率要远高于 .、:、\,反而与 "echo " 接近?
莫非  .、:、\ 效率低下的原因并不是对文件匹配?
测试代码:
  1. @echo off&setlocal enabledelayedexpansion
  2. for %%a in (" " . : \ + [ ]) do (
  3.         (set timea=!time!
  4.         for /l %%b in (1 1 10000) do echo%%~a
  5.         call :时差 !timea! !time!)>nul
  6.         echo 运行 10000 次 echo%%~a 的用时为: !时差!
  7. )
  8. pause
  9. :时差
  10. for /f "tokens=1-8 delims=:. " %%a in ("%*") do (
  11.         set /a "时差=(((%%e-%%a)*60+1%%f-1%%b)*60+1%%g-1%%c)*100+1%%h-1%%d"
  12. )
复制代码

TOP

本帖最后由 CrLf 于 2012-8-3 21:39 编辑

回复 5# Demon


    貌似我这帖子没有说过 echo. 具有通用性,只说过 echo( 在同条件下是十二种方案中通用性最强的一种,所以个人认为这是 echo 的最佳用法。
  那个转义的例子只是为了说明使用时可以将特殊字符转义避免错误解析,稍作引申罢了,若按老兄的角度来无限放大通用性的范围,那没有任何一种办法能在不转义的情况下 echo &、| 等 特殊字符,也没有办法 echo 超过 8187 字符(8192-5)长度的字符串了

TOP

回复 6# forfiles


    见 4 楼观点:
括号的错误匹配一向是发生在 ) 的多余和缺失上,与 ( 无关

TOP

本帖最后由 CrLf 于 2012-8-5 15:14 编辑

回复 8# Demon


试了下貌似测试结果浮动很大...建议使用 10000 以上的循环次数
另外建议在测试代码中这样:
(for /l %%a in (1 1 100000) do echo.)>nul
因为复合语句只需要一次 ReadFile 和后续预处理,对整个复合语句使用 >nul 也是同理,排除干扰后用时骤减。

比较奇怪的是,/ 虽然会被处理为 \,可用时却很低...

TOP

本帖最后由 CrLf 于 2012-8-7 18:22 编辑

回复 14# Demon


    win7 下测试无误,可是我无法理解 win7 下为何能直接 echo 8191 个字符,按理说就算是 echo 空行也要至少需要五个字符,cmd 不是一次性读入 8192 字节的吗?那么在 win7 下为何能从脚本一次性读入至少 8196 个字符?   
    顺便向老兄请教两个疑问,本地 vbs 有没有办法操作现存的 IE 页面,就像操作用 IE.Navigate 打开的页面那样?第二个问题,本地 vbs 该怎么调用 htm dom 中的脚本函数?

回复 16# qzwqzw


    题外话:发现变量值的上限不是以往认为的 8190 字符,而是 8191...
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (1 1 12) do set a=!a!!a!a
  3. ::此时变量 a 的值长度为 4095
  4. set a=!a!!a:~1!
  5. echo !a:~8188!
  6. ::此时变量 a 长度为 8189,这是常见赋值办法下的极限
  7. set;=!a!;
  8. echo !;:~8188!
  9. ::使用 ; , 这两个分隔符作为变量名可以“偷”一个字符长度
  10. set[=!;![
  11. echo ![:~8188!
  12. ::使用 [ ] + \ . 作为变量名居然还可以再偷一个字符长度...
  13. pause
复制代码

TOP

回复 18# qzwqzw


    多谢了,getobject 一直不会用,w3school 中的解释语焉不详,还以为不重要...

TOP

返回列表