一个函数能够访问和进一步处理另外一条命令的结果吗?答案是肯定的,这被称为管道。管道有两种模式,一种是顺序处理模式,一种是流处理模式。
低效率的顺序模式:$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 } }
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!
$host.ui.rawui.foregroundcolore 设置会导致屏幕所有字体颜色调整,而不是部分字的颜色调整,无法实现预计的效果.请博主检查下.
我的系统是PS V5 on Win10
输出不同色彩的字用Write-Host 效果好
你使用的肯定是 PowerShell ISE,使用 PowerShell 命令行就能实现博主的效果,不要问我是怎么知道的
楼主很强大,支持!