Powershell函数 过滤器 管道 4


一个函数能够访问和进一步处理另外一条命令的结果吗?答案是肯定的,这被称为管道。管道有两种模式,一种是顺序处理模式,一种是流处理模式。

低效率的顺序模式:$input

在最简单的情况下,你的函数不是真正支持管道。只能对前一个命令执行后的结果处理。前一个命令执行的结果通过被自动保存在$input变量中,$input是一个数组,它可以包含许多元素,一个元素,甚至一个元素都没有,这取决于具体的环境。

下面的例子,是一个函数,仅仅输出$input的内容。

PS E:mossfly.com> Function output
>> {
>>    $input
>> }
>>
PS E:mossfly.com> output
PS E:mossfly.com> 1,2,3 | output
1
2
3
PS E:mossfly.com> dir | output

    目录: E:mossfly.com

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         2012/2/28     23:34            a
d----         2012/2/28     23:35            b
d----         2012/2/28     23:35            c

到目前为止,这个函数只是仅仅输出了管道的结果,并没有其它比较强大的功能。在接下来的例子中,函数将会对管道的结果做进一步处理。函数名MarkEXE,将会检查Dir的结果,并高亮标记后缀名为EXE的文件名为红色。

Function MarkEXE
{
# 保存控制台当前的前景色
$oldcolor = $host.ui.rawui.ForegroundColor
# 通过循环逐条检查管道的结果
Foreach ($element in $input)
{
    # 如果后缀名为.exe,设置为前景色为红色
    If ($element.name.toLower().endsWith(".exe"))
    {
        $host.ui.Rawui.ForegroundColor = "red"
    }
    Else
    {
        # 否则恢复默认的前景色
        $host.ui.Rawui.ForegroundColor = $oldcolor
    }
    # 输出数组元素
    $element
}
# 最后,重置控制台的前景色:
$host.ui.Rawui.ForegroundColor = $oldcolor
}

过滤器:高效率 流模式

管道的低效率顺序模式在处理大容量数据时很容易出现问题,其结果是巨大的内存占用和进程等待。如果你的函数支持高效率的流模式,在处理管道结果时仅占用很小的内存。
事实上,针对之前MarkEXE函数,你只需要替换”function” 关键字 为 “filter”,它就会开始流模式处理,这样你再也不用过分的担心忍受程序的无休止的响应和崩溃的危险。你也可以递归处理全盘目录,甚至处理极其庞大的数据。例如:

Dir c: -recurse | MarkEXE

当MarkEXE每次被调用时,它只会对当前目录下的每个单独的元素进行处理。对于过滤器filters来说,$input 一直都是一个独立的元素。这也就是为什么在过滤器中$input一点用也没有的道理。此时,最好使用$_ 变量,因为它代表了当前处理的数据。这样还可以简化MarkExe,因为过滤器自身已经扮演了循环的角色了,你没有必要再写专门的循环处理了。

Filter MarkEXE
{
    # 记录当前控制台的背景色
    $oldcolor = $host.ui.rawui.ForegroundColor
    # 当前的管道元素保存在 $_ 变量中
    # 如果后缀名为 ".exe",
    # 改变背景色为红色:
    If ($_.name.toLower().endsWith(".exe"))
    {
        $host.ui.Rawui.ForegroundColor = "red"
    }
    Else
    {
        # 否则使用之前的背景色
        $host.ui.Rawui.ForegroundColor = $oldcolor
    }
    # 输出当前元素
    $_
    # 最后恢复控制台颜色:
    $host.ui.Rawui.ForegroundColor = $oldcolor
}

开发真正的管道函数

过滤器在函数中属于高级应用,因为它可以立即处理管道结果的每一个元素。但是过滤器必须每次重复执行预定义命令的结果。对于MarkEXE 函数,每次执行的过程中要记录和更新控制台的背景颜色,也要花费资源和时间。

事实上,过滤器只是特殊的函数。如果一个函数内部使用了管道,你就可以定义三个基础的任务区了:第一步,完成函数的初始化,完成函数执行的预备步骤;第二步处理递归调用所得的结果;最后进行收尾工作。 这三个任务区分别可以使用begin,process,end 语句块。

接下来把MarkEXE安装上面的模式进行改装:

Function MarkEXE
{
    begin
    {
        # 记录控制台的背景色
        $oldcolor = $host.ui.rawui.ForegroundColor
    }
    process
    {
        # 当前管道的元素 $_
        # 如果后缀名为 ".exe",
        # 改变背景色为红色:
        If ($_.name.toLower().endsWith(".exe"))
        {
            $host.ui.Rawui.ForegroundColor = "red"
        }
        Else
        {
            # 否则, 使用正常的背景色:
            $host.ui.Rawui.ForegroundColor = $oldcolor
         }
        # 输出当前的背景色
        $_
      }
    end
    {
        # 最后,恢复控制台的背景色:
        $host.ui.Rawui.ForegroundColor = $oldcolor
     }
}
本文链接: https://www.pstips.net/powershell-func-filters-pipeline.html
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!

关于 Mooser Lee

我是一个Powershell的爱好者,创建了PowerShell中文博客,热衷于Powershell技术的搜集和分享。本站部分内容来源于互联网,不足之处敬请谅解,并欢迎您批评指正。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

4 条评论 “Powershell函数 过滤器 管道