我喜欢 LIKE

使用 LIKE 运算符

Windows 管理规范查询语言 (WQL) 用于创建 WMI 查询,它是美国国家标准协会结构化查询语言 (ANSI SQL) 的一部分。

附注。我们相信,这句话创造了在“脚本专家”一句中使用大写词语数量的记录。

以下是更通俗易懂的说法:WQL 是 SQL 的一部分。坦率地讲:WQL 只是 SQL 的一小部分。如果您使用 SQL 和数据库编写过许多脚本,就一定使用过 UPDATE 查询、聚合函数、UNIONS、JOINS 以及各种其他高级技术。遗憾的是,WQL 中没有提供其中的许多技术。WQL 支持基本的 SELECT 查询,仅此而已。WQL 在技术(或功能)的任何方面均无法与 SQL 相媲美,而且短期内无法达到这种相当的水平。

不过,在 Windows Server 2003 和 Windows XP 中,WQL 新增了一项虽不起眼儿却非常有用的功能:LIKE 运算符。

本页内容

查询 WHERE 子句中的值
LIKE 运算符简介
使用通配符
创建“开头为”查询
创建“结尾为”查询
创建“包含”查询
使用一组字符
创建例外查询
使用单字符通配符

查询 WHERE 子句中的值

编写 WQL 查询时,通常查找的是“完整的”值。例如,如果想返回计算机上名称为 Scripts 的所有文件夹的集合,则需要使用与以下内容类似的查询:

"Select * From Win32_Directory Where FileName = 'Scripts'"

不过,有时您关注的是部分值而不是完整值,此时需要进行某种模式匹配。例如,假设有一组名称与以下内容类似的文件夹:

Scripts-1
Scripts-2
Scripts-3
Scripts-4

您清楚地知道自己想要做什么:您想要返回一个集合,其中包含名称以字符 Scripts- 开头(连字号后可能有某个其他字符或一组字符)的所有文件夹。在 Windows 2000 中,无法编写能够进行这种模式匹配的查询。您只能返回文件系统中所有文件夹的集合(这本身可能就是一个很漫长的过程),然后检查每个文件夹名称,看其是否与模式匹配。例如:

If (Left, objFolder.FileName, 8) = "Scripts-" Then

这种方法虽然有效,但无疑速度很慢,并且也不够巧妙。

LIKE 运算符简介

这正是 LIKE 运算符可以发挥作用的地方。可以使用 LIKE 运算符(同样只能在 Windows Server 2003 和 Windows XP 中使用)在查询中包含模式匹配。想要返回一个由名称以字符 Scripts- 开头的所有文件夹组成的集合吗?请使用以下查询:

"Select * From Win32_Directory Where FileName LIKE 'Scripts-%'"

我们稍后会说明该查询的工作方式。暂时可以这样讲,查询的内容基本上可以反映它的工作方式:“显示 FileName 属性值类似于 Scripts- 的所有文件夹的列表”。为什么不干脆说“...FileName 属性的值是‘Scripts-’...”呢?如果这样做的话,将只返回实际名称是“Scripts-”的文件夹。我们想要的不是名称本身就是“Scripts-”的文件夹,而是名称与之类似的文件夹。这就是我们使用 LIKE 运算符而不是等号的原因。

不要担心:我们会阐述如何在脚本中使用 LIKE 运算符。何时开始阐述?现在就开始如何?

使用通配符

LIKE 查询中最常用的字符可能就是 % 字符。% 字符的作用与命令外壳程序中使用的 * 通配符非常相似。例如,假设要列出文件名以字母 x 开头的所有文件。在命令提示符中键入以下内容并按 Enter 键,即可实现该目的:

dir x*

要列出以 x 结尾的所有文件名,请键入以下内容并按 Enter 键:

dir *x

最后一种情况,要列出文件名中的某个位置包含字母 x 的所有文件,请键入以下内容并按 Enter 键:

dir *x*

对您而言,以上内容多半是老调重弹,因为大多数系统管理员都知道 *(至少在 dir 命令中使用时)是一个通配符,表示“任意字符或一组字符”。例如,可以像下面这样解释命令“dir *x*”:“显示名称以任意字符(哪个字符都可以)开头、名称中的某个位置包含字符 x 并且以任意字符结尾的所有文件”。同样,命令“dir x*”的意思就是“显示名称以 x 开头,其后可以是任意字符(也可以没有任何字符)的所有文件。就是显示那些以 x 开头的文件”。

您是说对上述内容全都了解吗?好极了,这样在编写使用 LIKE 运算符的查询时就轻松多了。

创建“开头为”查询

在 WQL LIKE 查询中,% 的作用与 * 非常类似。例如,假设要列出名称以字母 x 开头的所有文件夹。以下就是用于完成此操作的脚本:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colFolders = objWMIService.ExecQuery _
    ("Select * From Win32_Directory Where FileName Like 'x%'")

For Each objFolder in colFolders
    Wscript.Echo "Name: " & objFolder.FileName
Next

请注意 WQL 查询和 WHERE 子句的结构,尤其是要注意 WHERE 子句的结构:

"Select * From Win32_Directory Where FileName Like 'x%'"

我们想要达到的目的是:“显示 FileName 属性以字母 x 开头的所有文件夹的列表”。就是这样,与命令“dir x*”非常相似。我们只是使用了 LIKE 运算符,并指定了文件名“x%”。还要注意,% 字符包含在单引号内;必须将通配符当作是文件夹名称本身的实际组成部分。

创建“结尾为”查询

以下是另一个示例。在此示例中,我们调换了 % 字符与字母 x 的位置:

"Select * From Win32_Directory Where FileName Like '%x'"

这是什么意思?它的含义是,现在我们要查找以 x 结尾的文件夹名称。我们不关心字母 x(也就是 % 字符)前面有哪些字符(或是否有字符);我们只关心最后一个字母恰好是 x。

以下是完整的脚本,它返回名称以 x 结尾的所有文件夹:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colFolders = objWMIService.ExecQuery _
    ("Select * From Win32_Directory Where FileName Like '%x'")

For Each objFolder in colFolders
    Wscript.Echo "Name: " & objFolder.FileName
Next

创建“包含”查询

又一个脚本。此脚本查找文件夹名称中的任意位置包含字母 x 的文件夹,这就是将字母 x 夹在两个 % 字符间的原因。我们不关心字母 x 前有哪些字符,也不关心字母 x 后有哪些字符。我们所要做的就是在文件夹名称中查找字母 x:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colFolders = objWMIService.ExecQuery _
    ("Select * From Win32_Directory Where FileName Like '%x%'")

For Each objFolder in colFolders
    Wscript.Echo "Name: " & objFolder.FileName
Next

当然,并不仅限于在查询中只使用一个字母。例如,要列出文件夹名称中包含 april 一词的所有文件夹,请使用以下查询:

"Select * From Win32_Directory Where FileName Like '%april%'"

使用一组字符

您会说,不错,已经相当好了。但假设您想获得名称以字母 x、字母 y 或字母 z 开头的所有文件夹的集合,是否只能使用各种 OR 运算符来编写查询(如下所示)?

"Select * From Win32_Directory Where FileName Like 'x%' OR FileName Like 'y%' OR FileName Like 'z%'"

不必如此。可以将这些字符括在方括号内来指定一组字符:[]。例如,如果要列出名称以 x、 y 或 z 开头的文件夹,请使用以下查询:

"Select * From Win32_Directory Where FileName Like '[xyz]%'"

在以上查询中,将三个目标字符“xyz”括在方括号内;此外,方括号(及括号内的字符)都位于单引号内。还要注意,此结构 - [xyz] - 的处理方式与任何其他字符完全一样。在上一查询中,字母 x 后跟 % 字符:‘x%’。在此查询中,[xyz] 字符后跟百分号字符:‘[xyz]%’。运行一下完整的脚本,看看效果如何:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colFolders = objWMIService.ExecQuery _
    ("Select * From Win32_Directory Where FileName Like '[xyz]%'")

For Each objFolder in colFolders
    Wscript.Echo "Name: " & objFolder.FileName
Next

创建例外查询

您说以上内容仍未正中下怀,这是何意?噢,一定是了:您想要检索的是名称不是以字母 x、y 或 z 开头的所有文件夹的集合。您猜怎么样?事实证明,使用 LIKE 查询就可以完成此项任务。您所要做的就是使用刚才示范的方法,即将所需字符集置于方括号内。不过,这一次要在这些字符前添加脱字号:^。脱字号指示脚本检索方括号内包含的字符以外的所有内容。要返回名称不是以 x、y 或 z 开头的所有文件夹,只需使用以下查询:

"Select * From Win32_Directory Where FileName Like '[^xyz]%'"

以下是用来执行该任务的完整脚本:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colFolders = objWMIService.ExecQuery _
    ("Select * From Win32_Directory Where FileName Like '[^xyz]%'")

For Each objFolder in colFolders
    Wscript.Echo "Name: " & objFolder.FileName
Next

是的:很酷。现在轮到最后一个查询了,看上去有点古怪,不过您可能会发现它非常有用。

使用单字符通配符

假设有一组名称与以下内容类似的文件夹:

b010105x
b010205x
b010305x
b010405x

换言之,每个文件夹名称均以字母 b 开头,然后是表示日期的六位数字(010105 表示 2005 年 1 月 1 日),最后是字母 x。多半没有办法编写一个查询来返回所有这些文件夹的列表,不是吗?

是啊,几乎无法做到。事实证明,可以使用下划线 (_) 来表示字符串中的任何单个字符。文件夹名称中的第一个字符已知:b。文件夹名称中的最后一个字母已知:x。我们还知道 b 和 x 间有六个字符,只是不能确定地知道这六个字符是什么。但那没有关系:我们使用与以下内容类似的查询就可以了,它使用六个下划线来表示六个未知字符:

"Select * From Win32_Directory Where FileName Like 'b______x'"

是的,我们知道它看上去怪怪的;我们可是告诉过您它的样子有点古怪。不过效果蛮好。以下是完整的脚本,可以自己试着运行一下:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colFolders = objWMIService.ExecQuery _
    ("Select * from Win32_Directory where FileName Like 'b______x'")

For Each objFolder in colFolders
    Wscript.Echo "Name: " & objFolder.FileName
Next

请注意,此类查询的运行速度相对较慢,查找字符串中的字符的任何查询都有这个缺点。(查找字符串开头或结尾处通配符的查询的运行速度要快得多。)尽管如此,查询效果很好,它将返回所有 b______x 文件夹的集合。最惬意的是,下次有人问你“您为何要升级到 Windows Server 2003?有什么是 2003 可以做到而 Windows 2000 做不到的吗?”,想象一下,当您向他们展示这个脚本时,您会有多么得意!