批处理技术内幕:IF命令

标签: , , , , ,

比起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

如果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函数,尝试将字符串转成整数:

wcstol

如果两边的字符串都可以完全被转成整数,那么会用左边的整数减去右边的整数,根据差与0的大小来决定哪个整数比较大。

sub

然而减法可能会导致溢出:

@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

拓展阅读:

赞赏

微信赞赏支付宝赞赏

随机文章:

  1. BinScope Binary Analyzer
  2. VBS中&H前缀十六进制数的陷阱
  3. 用C语言调用COM组件
  4. 将WMI中的DateTime类型转换成VBS时间
  5. 暴风一号病毒VBS源码解密

一条评论 发表在“批处理技术内幕:IF命令”上

  1. 解集SS说道:

    大神,那个看CPUthread的是什么软件啊?能不能发我邮箱c141028@163.com

留下回复