【问题标题】:Assigning a variable inside a switch statement在 switch 语句中分配变量
【发布时间】:2021-01-11 00:41:03
【问题描述】:

大家早上好!

自从我在另一篇文章中发现这个 switch 语句后,我就一直在搞乱它。

我在下面的代码中遇到了这个问题,它使用相同的信息打印多行,我知道为什么要这样做,但是我不知道如何解决它。我相信当我分配变量时它会搞砸,但我不太确定。有人可以指出我可能导致问题的正确方向吗?任何帮助表示赞赏。

$gc = Get-ChildItem -Path 'C:\users\abrah\OneDrive\Desktop'  
Foreach ($File in $gc) {
 
    switch -Wildcard ($file) {

        "deskt*" { $Desk = "This is the location: $($File.FullName)" }
        "*v*" { $VA = "This is the location: $($File.FullName)" }

    }

    $VCount = $va | Measure-Object | Select-Object -ExpandProperty Count
    $Dcount = $Desk | Measure-Object | Select-Object -ExpandProperty Count

    $PS = [pscustomobject]@{
        DesktopLocation = $Desk
        DCount          = $Dcount
        VLocation       = $VA
        VCount          = $VCount
 
    }

    $PS
}

关于脚本:我只是想在我的桌面上找到任何以deskt 开头的文件,以及其中包含字母V 的任何文件。然后我将它扔到一个自定义对象中,同时尝试计算有多少文件包含这些关键字母。

顺便说一下,结果如下:

【问题讨论】:

  • 我还想,“也许我可以只计算 customobject 中的项目,但是,那么我将如何附加到它呢?”
  • 您现在每次操作单个文件时都在尝试“重新计算”所有内容。一次做一件事,它会容易得多

标签: powershell


【解决方案1】:

至于您的基于switch-statement 的方法:

  • switch 本身能够处理集合,因此无需将其包装在foreach 循环中。

  • 您正在寻找的是从输入中构建两个集合,这需要您:

    • $Desk$VA 初始化为集合数据类型。
    • 追加switch分支处理程序中的这些集合。
# Initialize the collections.
$Desk = [System.Collections.Generic.List[string]] @()
$VA = [System.Collections.Generic.List[string]] @()

# Make `switch` loop over the .FullName values of all items in the target dir.
switch -Wildcard ((Get-ChildItem C:\users\abrah\OneDrive\Desktop).FullName) {
  '*\deskt*' { $Desk.Add("This is the location: $_") } # add to collection
  '*\*v*'    { $VA.Add("This is the location: $_") }   # add to collection
}

# Construct and output the summary object
[pscustomobject] @{
  DesktopLocation = $Desk
  DCount          = $Desk.Count
  VLocation       = $VA
  VCount          = $VA.Count
}

注意:

  • 虽然可以使用数组作为集合类型,但使用+=“追加”到数组虽然方便,但效率低下 em>,因为每次都必须在后台创建一个 数组,因为数组在元素计数方面是不可变的。
    虽然对于只有几个元素的数组可能无关紧要,但养成使用 System.Collections.Generic.List`1 作为高效可扩展集合类型的好习惯。

  • 也就是说,如果所有输出都被捕获在一个单个 集合,你甚至不需要显式的集合类型,既简洁又高效;例如:
    $collection = foreach ($i in 0..2) { $i + 1 } 将数组 1, 2, 3 存储在 $collection 中;注意如果只输出一个对象,$collection不是是一个数组,所以要确保你可以使用[array] $collection = ...


或者,更简单的解决方案是利用通过-Filter 参数进行基于通配符的过滤速度很快,因此即使调用Get-ChildItem两次 可能不会有问题:

$dir = 'C:\users\abrah\OneDrive\Desktop' 
[array] $Desk = (Get-ChildItem -LiteralPath $dir -Filter deskt*).FullName
[array] $VA = (Get-ChildItem -LiteralPath $dir -Filter *v*).FullName

[pscustomobject] @{
  DesktopLocation = $Desk
  DCount          = $Desk.Count
  VLocation       = $VA
  VCount          = $VA.Count
}

【讨论】:

  • Exception calling "Add" with "1" argument(s): "Collection was of a fixed size." 这是我在尝试运行第一个代码块时遇到的错误,第二个工作正常,但我不确定第一个为什么会这样。
  • 老实说,我只是想与switch 合作,看看它能做什么。我知道我可以用 6 种不同的方式来完成它,但是,我正在尝试一些尝试。真的是在尝试将这种新方法应用于 AD 查询,用于名称中包含某些单词的用户。
  • 明白了,@AbrahamZinala。至于错误消息:这意味着您使用了 array 而不是 [System.Collections.Generic.List[string]] 实例,如第一个 sn-p 所示。数组是固定大小的集合,但因为它们也实现了System.Collections.IList 接口,所以它们确实有一个.Add() 方法——总是失败。
  • 你有什么推荐我学习这些类型的东西的吗?书籍、视频、论坛?你似乎很了解这一点
  • @zett42:我从来没有真正研究过实现,但我认为一个ArrayList,它高效增长,在幕后使用,然后转换为数组。有点相关GitHub discussion。如果您想试验相对性能:$a = 1..1e6; Time-Command { $l = [System.Collections.Generic.List[object]] @(); foreach ($e in $a) { $l.Add($e) } }, { $l = foreach ($e in $a) { $e } }
【解决方案2】:

您不需要switchforeach 循环来计算与您拥有的每个模式匹配的文件数量:

# Fetch files
$gc = Get-ChildItem -Path 'C:\users\abrah\OneDrive\Desktop'  

# Count those starting with "Deskt"
$desktopFiles = $gc |Where-Object Name -like "Deskt*"

# Count those matching `*v*`
$vFiles = $gc |Where-Object Name -like "*v*"

# Output details
[PSCustomObject]@{
  DesktopLocations = @($desktopFiles.FullName)
  DesktopCount     = $desktopFiles.Count
  VLocations       = @($vFiles.FullName)
  VCount           = $vFiles.Count
}

【讨论】:

  • 感谢您的评论!只是想与switch 合作,看看它能做什么。
【解决方案3】:

其他解决方案:

$Grouped=Get-ChildItem -Path 'C:\users\abrah\OneDrive\Desktop'  -file | %{

if ($_.Name -like "Deskt*")
{
    Add-Member -InputObject $_ -MemberType NoteProperty -Name "TypeFile" -Value "DESK_FILE"
}
elseif ($_.Name -like "*v*")
{
   Add-Member -InputObject $_ -MemberType NoteProperty -Name "TypeFile" -Value "V_FILE"
}
else
{
   Add-Member -InputObject $_ -MemberType NoteProperty -Name "TypeFile" -Value "OTHER_FILE"
}

$_

} | Group TypeFile -AsHashTable

#result
$Grouped

#if you want files for a group 
$Grouped["V_FILE"] 

#if you want really your result
[PSCustomObject]@{
  DesktopLocations = $Grouped["DESK_FILE"].fullName 
  DesktopCount     = $Grouped["DESK_FILE"].Count
  VLocations       = $Grouped["V_FILE"].fullName 
  VCount           = $Grouped["V_FILE"].Count
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多