【问题标题】:Why can't i call Contains method from my array?为什么我不能从我的数组中调用 Contains 方法?
【发布时间】:2010-05-28 17:08:54
【问题描述】:

Arrrg!我遇到了一个我在 powershell 中编写的简单脚本的愚蠢问题。我正在调用一个调用存储过程的 sql 命令,结果我把它放在一个数组中。结果如下所示:

Status                                       ProcessStartTime                            ProcessEndTime                             
------                                       ----------------                            --------------                             
Expired                                      May 22 2010  8:31PM                         May 22 2010  8:32PM

我要做的是if($s.Contains("Expired")),报告失败。简单的...? :( 我遇到的问题是它看起来像 Contains 方法没有被加载,因为我收到这样的错误:

方法调用失败,因为 [System.Object[]] 不包含名为“包含”的方法。在行:1 字符:12 + $s.Contains

那么,我该怎么做才能阻止 powershell 将其展开为字符串?下面是实际的 ps 脚本 -

$s = @(Invoke-Sqlcmd -Query "USE DB
       GO
       exec Monitor_TEST_ps 'EXPORT_RUN',NULL,20" `
       -ServerInstance testdb002\testdb_002
      )

if ($s.Contains("Expired"))   
{
    Write-Host "Expired found, FAIL."
}
else 
{
    Write-Host "Not found, OK." 
}

【问题讨论】:

    标签: powershell


    【解决方案1】:

    简单地说,$s 是一个 .NET 数组(您使用 @() 确保这一点)并且您正在尝试调用此 .NET 类型上不存在的方法(包含)。

    解决问题的最简单方法是使用 PowerShell 的 -contains 运算符,它具有直接处理数组和进行不区分大小写比较的好处,例如:

    if ($s -contains 'expired') { ... }
    

    【讨论】:

    • 哇,我可以发誓我厌倦了。我现在觉得很傻,谢谢基思,它也很有效。 w00t.
    • 简单明了。正是我需要的。我在 PS 3 系统上进行开发,然后尝试在 PS 2 上运行我的代码。我收到此错误,这是解决问题的简单解决方案。
    【解决方案2】:

    您看到 Get-Members 方法的原因是 powershell 试图提供帮助并展开集合。如果您有一个包含多种类型项目的数组,它会向您显示每种类型的成员(例如,如果您是“ls”(Get-ChildItem)并且您所在的目录中有 FileInfos 和 DirectoryInfos,并且您使用管道 ls | gm ,它将向您显示 FileInfos 的成员以及 DirectoryInfos 的另一组成员):

    (7) C:\ -» ls
    
    
        Directory: C:\
    
    
    Mode                LastWriteTime     Length Name
    ----                -------------     ------ ----
    d----         5/28/2010   8:19 AM            .hg
    d----         5/13/2010   3:37 PM            Build
    …
    -a---         4/22/2010  11:21 AM       2603 TODO.org
    
    
    (8) C:\ -» ls | gm
    
    
       TypeName: System.IO.DirectoryInfo
    
    Name                      MemberType     Definition
    ----                      ----------     ----------
    Mode                      CodeProperty   System.String Mode{get=Mode;}
    Create                    Method         System.Void Create(System.Security.AccessControl.Direct...
    …
    
       TypeName: System.IO.FileInfo
    
    Name                      MemberType     Definition
    ----                      ----------     ----------
    Mode                      CodeProperty   System.String Mode{get=Mode;}
    AppendText                Method         System.IO.StreamWriter AppendText()
    …
    

    为了确保我没有查看展开的成员,我通常会先尝试“$s.GetType().Name”,看看我在处理什么。在您的情况下,它显然是数组,因为您将其初始化为“$s = @(Invo”(@ = 它是一个数组。)

    要查看数组是否包含项目,可以使用 -contains 运算符:

    (9) C:\ -» @(1,2,3) -contains 1
    True
    

    我认为你有一个字符串数组,所以你可以使用字符串字面量,比如:

    (10) C:\ -» @("Stuff","you've","got","might have","Expired") -contains "Expired"
    True
    

    但如果 expired 不是完全匹配(您正在寻找包含 expired 的元素,例如“Connection Expired 1/1/2010”),您需要找到匹配项并检查计数,我认为:

    (23) C:\ -» @("Stuff","you've","got","might have","Connection Expired 1/1/2010") -contains "Expired"
    False
    (24) C:\ -» @("Stuff","you've","got","might have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")}
    Connection Expired 1/1/2010
    (33) C:\ -» $xs = @("Stuff","you've","got","might have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")}
    (34) C:\ -» $xs.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     String                                   System.Object
    
    
    (35) C:\ -» $xs
    Connection Expired 1/1/2010
    

    在这种情况下,只有一个匹配项,因此 powershell 将其展开为一个字符串。混蛋。但是,如果有超过 1 个匹配项:

    (36) C:\ -» $xs = @("Stuff","you've","got","might Expired  have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")}
    (37) C:\ -» $xs.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     Object[]                                 System.Array
    
    
    (38) C:\ -» $xs
    might Expired  have
    Connection Expired 1/1/2010
    

    现在它是一个数组。

    幸运的是,字符串和数组都有一个长度属性:

    (39) C:\ -» $xs.Length
    2
    (40) C:\ -» "Bob".Length
    3
    

    因此您可以检查包含“已过期”的结果的长度,以查看是否有过期的:

    (41) C:\ -» $xs = @("Stuff","you've","got","might Expired  have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")} 
    (42) C:\ -» if ($xs.Length -gt 0) { Write-Host "Whoas, stuff's expired, dog." }
    Whoas, shit's expired, dog.
    

    (也许有人有更好的方法来检查集合是否包含满足某个谓词(如 LINQ 的 Any)的项目?)

    【讨论】:

    • 谢谢克里斯!这绝对让我朝着正确的方向前进。工作脚本: $s = @(Invoke-Sqlcmd -Query "USE DB GO exec Monitor_TEST_ps 'EXPORT_RUN',NULL,20 " ` -ServerInstance "testdb002\testdb_002") if ($s | ?{ $_['Status'] -eq 'OK'}) { Write-Host "已过期,失败。" } else { 写主机“未找到,好的。” }
    猜你喜欢
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-13
    • 2010-11-28
    • 2011-12-09
    • 2013-07-09
    • 2022-10-04
    相关资源
    最近更新 更多