标题: 批处理技术内幕:IF命令
作者: Demon
链接: https://demon.tw/reverse/cmd-internal-if.html
版权: 本博客的所有文章,都遵守“署名-非商业性使用-相同方式共享 2.5 中国大陆”协议条款。
比起ECHO的简单,IF命令似乎要复杂得多,至少帮助文档的文字要多得多。
IF [NOT] ERRORLEVEL number command IF [NOT] string1==string2 command IF [NOT] EXIST filename command
如果CMD拓展开启(ENABLEEXTENSIONS)的话,IF还支持下面的用法:
IF [/I] string1 compare-op string2 command IF CMDEXTVERSION number command IF DEFINED variable command
compare-op可以是下列之一:
EQU - equal NEQ - not equal LSS - less than LEQ - less than or equal GTR - greater than GEQ - greater than or equal
你可能要说,这些地球人都知道的东西你复制粘贴上来做什么?跟批处理技术内幕有半毛钱关系?
其实我也不想,可是我实在不知道怎么写开头。我们从最简单也是最常用的if string1==string2讲起:
@echo off set /p str=What's the domain of Demon's Blog: if %str%==demon.tw start https://demon.tw pause
当然,为了防止用户没有输入或者输入中含有特殊字符而导致的脚本解析错误,最佳实践是在两边都加上双引号,同时也可以加上空格以提高可读性:
@echo off set /p str=What's the domain of Demon's Blog: if "%str%" == "demon.tw" start https://demon.tw pause
CMD是如何比较两个字符串是否相等的呢?其实它只做了一件事:调用lstrcmp函数:
如果lstrcmp函数认为两个字符串相等,则if条件成立。
lstrcmp应该是Locale String Compare的缩写,根据MSDN文档,它会以当前线程的Locale调用CompareString函数,将返回的结果减去2以符合C语言字符串比较函数的返回值约定(1表示大于,0表示等于,-1表示小于)。CompareString函数进行的是语言排序(Sort Linguistically)而不是二进制排序,如果两个字符串的二进制不同但是代表的语言文字相同,那么lstrcmp函数仍然会认为它们相等,这和C语言的字符串比较函数是不同的:
#include <stdio.h> #include <string.h> #include <Windows.h> int main() { wchar_t s1[] = {0x00E9, 0x0000}; wchar_t s2[] = {0x0065, 0x0301, 0x0000}; printf("%d\n", wcscmp(s1, s2)); printf("%d\n", lstrcmpW(s1, s2)); return 0; }
U+00E9和U+0065 U+0301的组合都可以表示é这个字符,但它们的二进制表示却不同,C语言函数wcscmp认为它们并不相等,而lstrcmp却认为它们是相等的。
除了语言排序(Sort Linguistically)之外,CompareString函数默认使用的是单词排序(word sort)而不是字符串排序(string sort)。在单词排序中,除了连字号(hyphen)-和撇号(apostrophe)’之外的所有标点符号(punctuation marks)和其他非字母数字字符(nonalphanumeric characters)都排在字母数字字符(alphanumeric character)的前面。区别对待连字号-和撇号’以保证coop和co-op、cant和can’t之类的单词排列在一起。
@echo off if 0xff gtr 0200 echo 255 ^> 128 pause
equ neq lss leq gtr geq的实现和==差不多,只不过比==更智能一点,在进行字符串比较之前,CMD会首先会调用wcstol函数,尝试将字符串转成整数:
如果两边的字符串都可以完全被转成整数,那么会用左边的整数减去右边的整数,根据差与0的大小来决定哪个整数比较大。
然而减法可能会导致溢出:
@echo off if 2147483647 lss -2147483648 echo 2147483647 ^< -2147483648 pause
2147483647 – (-2147483648) = 4294967295,即十六进制的0xFFFFFFFF,由于是有符号整数,它代表-1,而-1<0,所以CMD认为2147483647 < -2147483648。
如果两边的字符串其中有一个无法转成整数,那么和==一样,也是调用lstrcmp来比较字符串的大小。
如果if加上了/i开关,处理方式也是大同小异的,只不过lstrcmp变成了lstricmp而已。
if的其他几种用法都比较简单,没什么内幕好讲的,就不多说了。
参考链接:http://msdn.microsoft.com/en-us/library/windows/desktop/dd318144%28v=vs.85%29.aspx
拓展阅读:
- http://bbs.bathome.net/viewthread.php?tid=7513
- http://bbs.bathome.net/viewthread.php?tid=6853
- http://bbs.bathome.net/viewthread.php?tid=14681
- http://bathome.net/viewthread.php?tid=12329
微信赞赏支付宝赞赏
随机文章:
大神,那个看CPUthread的是什么软件啊?能不能发我邮箱c141028@163.com