解决DOS批处理中一个困扰我几十个月的编码问题
DOS批处理中的编码很有意思。&是命令连接符,先执行&左边的命令,再执行&右边的命令。|是管道操作,把左边的输出当作右边的输入。此外还有&&和||,当要表示这些特殊的字符本身的时候,得在左边加^号,如用^&表示&本身,而不是命令连接符。^^表示^。
我有一个批处理myfor.bat, 可以重复N次执行命令, 命令从参数传入。它很简单:
@Echo Off
set /a i=%1
:start
%~2
set /a i=i-1
if %i% GTR 0 goto start
参数1是执行的次数,参数2是要执行的命令。
这次的实际任务就是重复地执行ping,要ping n个IP,我不想开n个窗口。所以命令是这样的: myfor 999 "ping 10.0.0.1&ping 10.0.0.2&ping 10.0.0.3" 。是的没错,双引号的优先级大于&,所以双引号中的&不需要加^,我也是实测发现的。每个ping的结果是这样的:
正在 Ping 10.0.0.1 具有 32 字节的数据:
来自 10.0.0.1 的回复: 字节=32 时间<1ms TTL=64
来自 10.0.0.1 的回复: 字节=32 时间<1ms TTL=64
来自 10.0.0.1 的回复: 字节=32 时间<1ms TTL=64
来自 10.0.0.1 的回复: 字节=32 时间<1ms TTL=64 10.0.0.1 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 0ms,最长 = 0ms,平均 = 0ms
为了只看延时,过滤掉统计信息和空行,我加了个Find,只显示带有“来自”的行: myfor 999 "ping 10.0.0.1|find "来自"&ping 10.0.0.2|find "来自"&ping 10.0.0.3|find "来自"" 。
然后,因为这条命令最近经常要执行,而且IP还不是固定的,于是我想能不能做成一个批处理plist.bat。用的时候就这样用: plist 10.0.0.1 10.0.0.2 10.0.0.3 。思路很简单,就是通过shift循环取到每个参数,并拼成类似这样的字符串: "ping 10.0.0.1|find "来自"&ping 10.0.0.2|find "来自"&ping 10.0.0.3|find "来自"" ,然后传给myfor去执行。
@Echo Off
cls
set cmd=ping %1 ^| find "来自"
shift
:forIps
if "%1"=="" goto :exitIps
set cmd=%cmd% ^& ping %1 ^| find "来自"
shift
goto :forIps
:exitIps
echo myfor 999 "%cmd%"
myfor 999 "%cmd%"
我执行了: plist.bat 10.0.0.1 10.0.0.2 10.0.0.3 ,出现:
找不到文件 - &
找不到文件 - PING
找不到文件 - 10.0.0.2
找不到文件 - |
找不到文件 - FIND
找不到文件 - 来自
找不到文件 - &
找不到文件 - PING
找不到文件 - 10.0.0.3
找不到文件 - |
找不到文件 - FIND
找不到文件 - 来自
myfor 999 "ping 10.0.0.3 | find "来自""
来自 10.0.0.3 的回复: 字节=32 时间<1ms TTL=64
来自 10.0.0.3 的回复: 字节=32 时间<1ms TTL=64
怎么回事? 分析了一下, 关键在set cmd这条命令: set cmd=ping %1 ^| find "来自" 实际执行了 set cmd=ping 10.0.0.1 ^| find "来自" 这个没问题。然后执行了 set cmd=%cmd% ^& ping %1 ^| find "来自" 实际执行了 set cmd=ping 10.0.0.1 | find "来自" ^& ping 10.0.0.2 ^| find "来自" 正是^|已经被解析成了|, 从而命令的意思是把 set cmd=ping 10.0.0.1 的输出当作find 的输入,而find右边的全部内容都被当作find的参数,于是出现“找不到文件 - &” 等错误。分析了这么多,根源在于最左边的|被解析成管道操作,而不是当作普通的字符串,要知道这里是要拼接字符串,此时得当作普通字符,等到要执行的时候,才当作管道。
那好,我就在拼接前把|变成^|, 改成这样子:
@Echo Off
cls
set cmd=ping %1 ^| find "来自"
shift
:forIps
if "%1"=="" goto :exitIps
set cmd=%cmd:|=^^^|%
set cmd=%cmd% ^& ping %1 ^| find "来自"
shift
goto :forIps
:exitIps
echo myfor 999 "%cmd%"
myfor 999 "%cmd%"
执行: plist.bat 10.0.0.1 10.0.0.2 10.0.0.3 出现:
错误的参数 ^|。
myfor 999 "ping 10.0.0.1 | find "来自" & ping 10.0.0.3 | find "来自""
分析原因, 关键还是在这一行 set cmd=%cmd:|=^^^|% 。为了不让|生效,我们需要将|替换成^|,为了不让&生效,我们需要将&替换成^&,但我们替换|的时候&生效了,我们替换&的时候|生效了。先替换哪个都有问题。思路卡住了,这一卡就卡了几十个月。
真的没有出路了吗?我们是希望每次拼接完是可以执行的语句,即&和|左边刚好没有^,所以才会卡住。但如果我们退一步,每次拼接完&和|左边都只有1个^,然后在执行前再把这个^去掉,这条路是否行得通?去掉^非常简单,就是这么一句 set cmd=%cmd% 。由于每次拼接完&和|左边要有一个^,所以原来的 set cmd=ping %1 ^| find "来自" 得变成 set cmd=ping %p1% ^^^| find "来自" ,其它情况类似。由于&和|左边都有^,所以每次我只需要控制^的数量,就可以防止^&和^|被解码。经过一番修改、调试、再修改。最终可行的版本浮现了:
@Echo Off
cls
set cmd=ping %1 ^^^| find "来自"
shift
:forIps
if "%1"=="" goto :exitIps
set cmd=%cmd:^=^^^^^^^%
set cmd=%cmd% ^^^& ping %1 ^^^| find "来自"
shift
goto :forIps
:exitIps
set cmd=%cmd%
echo myfor 999 "%cmd%"
myfor 999 "%cmd%"
执行: plist.bat 10.0.0.1 10.0.0.2 10.0.0.3 出现:
myfor 999 "ping 10.0.0.1 | find "来自" & ping 10.0.0.2 | find "来自" & ping 10.0.0.3 | find "来自""
来自 10.0.0.1 的回复: 字节=32 时间<1ms TTL=128
来自 10.0.0.1 的回复: 字节=32 时间<1ms TTL=128
来自 10.0.0.1 的回复: 字节=32 时间<1ms TTL=128
来自 10.0.0.1 的回复: 字节=32 时间<1ms TTL=128
来自 10.0.0.2 的回复: 字节=32 时间<1ms TTL=128
来自 10.0.0.2 的回复: 字节=32 时间<1ms TTL=128
来自 10.0.0.2 的回复: 字节=32 时间<1ms TTL=128
……
大功告成。
到了山穷水尽疑无路的境地, 退一步却迎来了柳暗花明又一村。这个解决方案不仅用于这个交替ping,在我的其它工具也会用到,它对我而言,意义重大。读者朋友你们的网络中不一定有10.0.0.*这样的IP,因为使用了find过滤,所以ping不存在的ip是不会有显示的。所以测试时为了尽最大可能的成功,可以替换成 127.0.0.1 127.0.0.2 127.0.0.3。
对于Dos shell,虽然不像linux shell那么强大,但是适用就是好猫。而对于只要%cmd%就会自动解码这种方式,有时会带来棘手的编码问题,就如本文的这个问题,是我遇到的最难处理的dos shell编码问题了。既然已找到我自己满意的解法,以后就可以大胆地移值到其它类似的棘手的编码问题上。
解决DOS批处理中一个困扰我几十个月的编码问题的更多相关文章
- DOS批处理中对含有特殊字符的文件名的处理方法
从一些网站下载的文件,文件名带有广告,典型的就是网站的名称和域名,搞得文件名很长.在一些场景下,广告看得见,真正的文件名却被...了.在以前,我是遇到就手工去掉广告,但一是麻烦,二是效率低.反正经常下 ...
- DOS批处理中%cd%与%~dp0的区别详解
转载:https://www.jb51.net/article/105325.htm DOS批处理中%cd%与%~dp0的区别详解 Windows下批处理中%cd%和%~dp0都能用来表示当前 ...
- DOS批处理中%cd%和%~dp0的区别
DOS批处理中%cd%和%~dp0的区别 在DOS的批处理中,有时候需要知道当前的路径. 在DOS中,有两个环境变量可以跟当前路径有关,一个是%cd%, 一个是%~dp0. 这两个变量 ...
- DOS批处理中%cd%和%~dp0的区别[forward]
DOS批处理中%cd%和%~dp0的区别 在DOS的批处理中,有时候需要知道当前的路径. 在DOS中,有两个环境变量可以跟当前路径有关,一个是%cd%, 一个是%~dp0. 这两个变量的 ...
- DOS批处理中%~dp0表示什么意思
https://www.jianshu.com/p/5a1a882ead95 https://www.cnblogs.com/cnpirate/p/5282324.html https://www.c ...
- DOS批处理中%~dp0等扩充变量语法详解
有时候我们看到别人使用%~dp0 ~是扩展的意思,相当于把一个相对路径转换绝对路径%0代指批处理文件自身%1表示批处理文件命令行接收到的第一个参数,%2表示第二个,以此类推%~d0 是指批处理所在的盘 ...
- 转载:dos批处理中路径获取
在DOS的批处理中,有时候需要知道当前的路径. 在DOS中,有两个环境变量可以跟当前路径有关,一个是%cd%, 一个是%~dp0. 这两个变量的用法和代表的内容是不同的. 1. %cd% ...
- DOS批处理中%cd%和%~dp0的异同分析
在DOS的批处理中,有时候需要知道当前的路径.在DOS中,有两个环境变量可以跟当前路径有关,一个是%cd%, 一个是%~dp0. 这两个变量的用法和代表的内容是不同的. 1. %cd% 可以用在批处理 ...
- dos 批处理中%cd% 和%~dp0%的区别
看网上介绍区别,写的好复杂,其实很简单: %cd% 在批处理和命令窗口都能使用.用于打印,当前工作路径. %~dp0% 则只能用于批处理中,用于获得当前批处理文件所在的路径. 做个试验试一下: @e ...
随机推荐
- 2018/2/13 ElasticSearch学习笔记三 自动映射以及创建自动映射模版,ElasticSearch聚合查询
终于把这些命令全敲了一遍,话说ELK技术栈L和K我今天花了一下午全部搞定,学完后还都是花式玩那种...E却学了四天(当然主要是因为之前上班一直没时间学,还有安装服务时出现的各种error真是让我扎心了 ...
- Windows Server 2016-部署额外域控制器
我们一般所提到的所谓域外控制器,是指除域内第一台域控制器之外的其他域控制器.额外域控制器很多时候也有辅助域控一称.那么在同一域内安装多台域控制器有什么优点呢: 1.提高用户登录效率.多台域控制器可以同 ...
- Windows Server 2016-图形化迁移FSMO角色
上章节我们简单介绍了三种不同方式查看FSMO主机角色信息,在开篇之前我们简单回顾一下FSMO五种操作主机角色:林范围操作主机角色有两种,分别是 架构主机角色(Schema Master)和 域命名主机 ...
- arm 异常处理结构
概念:正常的程序执行过程中发生暂时的停止称为异常,如果发现异常情况,将会进行异常处理 作用:快速响应用户的行为,提高cpu的响应能力 异常类型: 异常处理的三个步骤: 1.保护现场: 工作模式保存:C ...
- SQL替换语句 批量修改、增加、删除字段内容
sql替换语句,用该命令可以整批替换某字段的内容,也可以批量在原字段内容上加上或去掉字符. 命令总解:update 表的名称 set 此表要替换的字段名=REPLACE(此表要替换的字段名, '原来内 ...
- Yii2重置密码
//Yii框架下hash密码正确的比较方法$result = Yii::$app->security->validatePassword($password, $hash);echo $r ...
- php的内置函数debug_backtrace()与get_included_files()跟踪代码调用(Thinkphp框架举例)
debug_backtrace() 在我们开发一个项目中,或者二开研究某个开源程序,需要对代码流程一步步去跟踪,来研究它的逻辑,才可以进行修改,达到我们的开发目的.php的内置函数debug_back ...
- Asp.Net Core Identity+EFCore + Mysql踩坑记录
搭建基础框架准备试试传说中的Identity,本以为很顺利,结果一路踩了N多坑 遂就把过程记录下来.方便自己以后查看,也希望能帮到遇到同样问题的朋友. 1.首先,引入Identity需要的类库,还有M ...
- 剑指offer面试题-Java版-持续更新
最近在用Java刷剑指offer(第二版)的面试题.书中原题的代码采用C++编写,有些题的初衷是为了考察C++的指针.模板等特性,这些题使用Java编写有些不合适.但多数题还是考察通用的算法.数据结构 ...
- POJ - 1733 Parity game 种类并查集+离散化
思路:d(i, j)表示区间(i, j]的1的个数的奇偶性.输入最多共有5000*2个点,需要离散化处理一下.剩下的就是并查集判冲突. AC代码 #include <cstdio> #in ...