找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 64776|回复: 21

[原创] 批处理命令连接符号优先级证明

[复制链接]
发表于 2012-3-22 21:32:32 | 显示全部楼层 |阅读模式

  1. @echo off
  2. echo.
  3. echo.    已经确认命令连接符号优先级从低到高如下:
  4. echo.            ^&               命令分隔符
  5. echo.            ^|^|          逻辑或操作符
  6. echo.            ^&^&          逻辑与操作符
  7. echo.            ^|           管道操作符
  8. echo.            ^< ^> ^>^>      I/O重定向操作符
  9. echo.            ^(^)          命令分组
  10. echo.
  11. echo.证明过程如下:
  12. pause
  13. echo.
  14. echo.  首先应当公认^(和^)作为命令分组符号有最高的优先级,可以改变任意命令组的优先级
  15. echo.
  16. echo.  另外需要注意的是,命令连接符号的优先级与语句的执行顺序不是直接对应的
  17. echo.
  18. echo.  命令行中的语句仍然是先执行左侧,再执行右侧
  19. echo.
  20. echo.  命令连接符只影响左侧与右侧语句的分组过程,而不会使右侧语句先执行
  21. echo.
  22. pause
  23. cls
  24. echo on
  25. echo flag1 | echo flag2 > con
  26. echo flag1 | (echo flag2 > con)
  27. (echo flag1 | echo flag2) > con
  28. @echo off
  29. echo.
  30. echo.前两句输出效果相同,说明第二句的分组符号可以省略,证明 ^> 优先级大于 ^|
  31. pause

  32. cls
  33. echo on
  34. echo flag1 && echo flag2 | echo flag3
  35. echo flag1 && (echo flag2 | echo flag3)
  36. (echo flag1 && echo flag2) | echo flag3
  37. @echo off
  38. echo.
  39. echo.前两句输出效果相同,说明第二句的分组符号可以省略,证明 ^| 优先级大于 ^&^&
  40. pause

  41. cls
  42. echo on
  43. echo flag1 || echo flag2 && echo flag3
  44. echo flag1 || (echo flag2 && echo flag3)
  45. (echo flag1 || echo flag2) && echo flag3
  46. @echo off
  47. echo.
  48. echo.前两句输出效果相同,说明第二句的分组符号可以省略,证明 ^&^& 优先级大于 ^|^|
  49. pause

  50. cls
  51. echo on
  52. echo flag1 || echo flag2 & echo flag3
  53. (echo flag1 || echo flag2) & echo flag3
  54. echo flag1 || (echo flag2 & echo flag3)
  55. @echo off
  56. echo.
  57. echo.前两句输出效果相同,说明第二句的分组符号可以省略,证明 ^|^| 优先级大于 ^&
  58. pause

  59. cls
  60. echo.综合测试示例:
  61. echo.
  62. echo on
  63. echo flag1 & more flag2 || echo flag3 && echo flag4 | echo flag5 || echo flag6
  64. echo flag1 & ((more flag2 || (echo flag3 && (echo flag4 | echo flag5))) || echo flag6)
  65. (echo flag1 & (more flag2 || (echo flag3 && echo flag4) | echo flag5)) || echo flag6
  66. @echo off
  67. echo.
  68. echo.前两句输出效果相同,说明符合优先级和分组优先级相同,第三句是个反例
  69. pause
复制代码

评分

参与人数 2PB +5 技术 +2 收起 理由
plp626 + 1 有意思
CrLf + 5 + 1 感谢总结分享

查看全部评分

发表于 2012-3-22 23:07:21 | 显示全部楼层
有意思,先支持一下!
发表于 2012-3-22 23:30:05 | 显示全部楼层
本帖最后由 CrLf 于 2012-3-22 23:39 编辑
  1. (echo flag1 | echo flag2) > con
复制代码
什么情况,这句在我电脑上似乎也出现了内存泄露?win7 系统,求验证及解答
另外,我觉得楼主对重定向符的优先级验证不严谨吧,应该这样证明:
  1. set =|find /c "" 2>nul
  2. (set =|find /c "") 2>nul
  3. set = 2>nul|find /c ""
复制代码
发表于 2012-3-23 08:50:21 | 显示全部楼层
本帖最后由 plp626 于 2012-3-23 08:53 编辑

回复 3# CrLf


    你的“内存泄露”显示的是?
我这里:
  1. flag2&#9834;&#9689;
复制代码
比较惊讶的是后面两个特殊字符到底是什么?
发表于 2012-3-23 09:04:55 | 显示全部楼层
回复 4# plp626


    显示是这样的,多显示了两个没见过的字符。话说让我吃惊的是,执行到这里时居然惊动了 360:
   
    而我电脑上的 0x0~0xff 应显示为:
   

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 发表于 2012-3-23 13:28:54 | 显示全部楼层
实际上那两个字符就是你的ID的“原形”
用这种方法还能显示出0x08 0x09等字符
 楼主| 发表于 2012-3-23 13:41:11 | 显示全部楼层
版主再仔细推敲一下你的证明代码
我觉得逻辑上似也有问题

至于我的证明代码
一方面因为我是先通过其它方法确认了这个优先级
再去寻求从代码角度证明的
另一方面为了追求代码的优雅
设计上主要考虑了前后代码的连贯性
所以有些逻辑上的疏忽在所难免

当然重定向符号的细节还比较多
包括句柄复制符号也没有展开来
发表于 2012-3-23 13:47:35 | 显示全部楼层
本帖最后由 plp626 于 2012-3-23 14:16 编辑

这个副产品有意思。。。cmd的黑框显示的字符还真多。。。下次准备更新 ascii.cmd
  1. cmd/v
  2. call ascmap.cmd $
  3. (echo;|echo off)>con&echo !$:~0,70!
复制代码
发表于 2012-3-23 16:20:03 | 显示全部楼层
本帖最后由 CrLf 于 2012-3-23 16:23 编辑

回复 6# qzwqzw


噢,果然如此,写成这样和 dir 的结果一比较就很明显了:
  1. (echo;|dir)>con
复制代码
但是不知为何会因为重定向而导致回车换行符显现真身呢?08、09 确实试出来了,但是不知其所以然
  1. (echo;|set /p=        )>con
  2. rem 长串空格为一个 tab 制表符
复制代码
 楼主| 发表于 2014-11-27 10:41:30 | 显示全部楼层
本帖最后由 qzwqzw 于 2014-11-27 10:52 编辑

现在基本可以确定
| 和>这些符号会影响cmd的控制台IO模式
而这些模式会影响等控制台标准IO函数的行为
主要包括ReadFile/ReadConsole,WriteFile/WriteConsole
3,8,9楼的代码
主要是因为ENABLE_PROCESSED_OUTPUT模式被置假
导致WriteFile/WriteConsole不再特殊处理屏幕缓冲区中的控制区字符

可用的模式共

  1. ENABLE_ECHO_INPUT                        0x0004
  2. ENABLE_EXTENDED_FLAGS                0x0080
  3. ENABLE_INSERT_MODE                        0x0020
  4. ENABLE_LINE_INPUT                        0x0002
  5. ENABLE_MOUSE_INPUT                        0x0010
  6. ENABLE_PROCESSED_INPUT                0x0001
  7. ENABLE_QUICK_EDIT_MODE                0x0040
  8. ENABLE_WINDOW_INPUT                        0x0008
  9.                         
  10. ENABLE_PROCESSED_OUTPUT                0x0001
  11. ENABLE_WRAP_AT_EOL_OUTPUT        0x0002
复制代码
参考链接
http://msdn.microsoft.com/en-us/library/ms686033(VS.85).aspx
发表于 2014-11-27 12:56:20 | 显示全部楼层
让我想起了批处理内幕:句柄 那篇帖子了,后面有一个句柄转换后把con重新指给1句柄的,那里面就出现了cls控制字符的显示,看来根源也在这里。
 楼主| 发表于 2014-11-28 17:39:26 | 显示全部楼层
本帖最后由 qzwqzw 于 2014-11-28 17:44 编辑

回复 11# amwfjhh

    让我想起了批处理内幕:句柄 那篇帖子了,后面有一个句柄转换后把con重新指给1句柄的,那里面就出现了cls控制字符的显示,看来根源也在这里。


你说的应该是《重定向中的秘密(句柄备份)》的27楼的问题
http://www.bathome.net/redirect. ... 92&fromuid=3023

两个问题其实并非同源
那里的问题主要是因为con并非完全仿真的控制台
导致cls以及dir/p等命令识别出了这个特殊设备
所以在显示逻辑上做了例外处理
在真正的控制台上cls不会输出0x0c的字符

这里的问题主要是管道、重定向以及括号字符的联用
导致控制台的IO模式发生变化
最终忽略了缓冲区中控制字符的特殊处理

你可以注意到两个问题的命令行用法并不完全相同
echo.>con并不会输出0x0d 0x0a的图形字符
echo+0x0c(可以通过Ctrl-L输入)也不会执行清屏
发表于 2014-11-28 17:44:09 | 显示全部楼层
回复 12# qzwqzw


    (echo,|set a=&cls)>con
 楼主| 发表于 2014-11-28 17:52:10 | 显示全部楼层
本帖最后由 qzwqzw 于 2014-11-28 17:54 编辑

回复 13# amwfjhh


    你想通过这段代码说明什么?

代码中>con会将标准输出重定向到con
而cls执行时会探测到标准输出不再是原来的控制台
因此直接输出字符了事
发表于 2014-11-28 18:37:15 | 显示全部楼层
话说句柄默认输出就是标准设备,那么可以这样:
  1. (cls 1>&2)>nul
  2. pause

  3. (cls 1>&3)>nul
  4. pause
复制代码
测试中从句柄 4 开始都不能放在 >& 之后,会报这个错误:
  1. 重定向句柄 N 时,
  2. 无法复制此句柄。
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-17 07:28 , Processed in 0.023869 second(s), 9 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表