首页 > 解决方案 > PowerShell | Get-ChildItem 通过管道不提供所有项目的功能

问题描述

由于 Azure Dev Ops 在部署时将 LF 转换为 CRLF,我必须创建一个自定义函数来搜索 .sh 文件并将它们转换回它们在 repo (LF) 中的存储方式。该代码我很好,但是我真的想制作一个很棒的函数,我可以执行一个 get-childitem 递归查找 .sh 文件,然后将其传递给我的自定义函数,该函数会将它们恢复为正确的格式。

我的问题是我、get-childitem 和函数不能相处。

为了让这个只关注主要问题,这里有一个过于简单的示例函数:

Function List-Items {
    param (
        [Parameter(ValueFromPipeline = $true)]$items
    )

    Write-Output "Item Count: $($items | Measure-Object | select -ExpandProperty Count)"
    foreach ($item in $items) {
        Write-Output "Item: $($item)"
    }
}

我称之为:

dir c:\temp\ | List-Items

然而,即使通过此命令显然有 52 个项目: dir c:\temp\ | Measure-Object

该函数只看到这 52 条记录中的最后一条记录。如何在我的自定义列表项函数中访问所有 52 条记录?

标签: powershell

解决方案


这是预期的行为。实际上,PowerShell 中的高级函数具有三个不同的块

  • begin- 在管道开始执行之前运行一次
  • process-为每个管道绑定输入项运行一次
  • end-在上游 cmdlet 完成发送输入运行一次

当您没有指定任何这些不同的块时,只有一个函数体,例如您的示例:

Function List-Items {
    param (
        [Parameter(ValueFromPipeline = $true)]$items
    )

    # Do stuff with $items

}

它实际上相当于:

Function List-Items {
    param (
        [Parameter(ValueFromPipeline = $true)]$items
    )

    end {
        # Do stuff with $items
    }
}

换句话说,函数体默认充当end块,这就是为什么您只看到绑定到的最后一个值$items

要解决此问题,请显式指定一个process块:

Function List-Items {
    param (
        [Parameter(ValueFromPipeline = $true)]$items
    )

    process {
        foreach ($item in $items) {
            Write-Output "Item: $($item)"
        }
    }
}

推荐阅读