这一章谈谈ps的管道通信,函数和过滤器。这仨哥们之间有着千丝万缕的联系。当然,跟我比较懒,不想写三篇来介绍也有关。
什么是管道?简单来说,管道就是一种函数的组合,类似于B(A(X)),就是把一个函数的输入作为一个函数的输出,他有一定的局限性,你最多只能..D(C(B(A(X)))),而不能D(C
(X),B(X),A(X))。这个关于管道的解释我觉得比较通俗易懂,我是从另一个博主的博文中摘取的,原文在王垠:Unix的缺陷。这是一篇介绍Unix的哲学缺陷的文章,其中说到的用文
本流作为程序通用接口的缺陷我在ps中没有发现,应该是因为ps是建立在CTS(通用类型系统)上的原因,所以ps支持多种类型。
什么是函数?有你的初中老师数学电话没?打过去问他。(计算机的中的函数概念可能和数学中的有区别,但我觉得数学中对函数的定义更加的严谨)
什么是过滤器?过滤器在ps中可以算是一种特殊的函数。
在ps中管道通信使用“|“这个操作符,一个函数组合D(C(B(A(X))))可以表达为A(X)|B(X)|C(X)|D(X)。
假设如下情景,你需要获得每一个进程的详细信息并且将他们输出到一个txt文件,那么你要做两件事
(1)获得所有的进程。get-process
(2)输出他们到txt文件。set-conent process.txt
用管道表达就是:get-process|set-conent process.txt
打开process.txt你会发现其中的内容与输出到控制台的内容并不相同,那是因为get-process返回的是一个进程对象,输出到控制台的内容经过了处理。
既然管道函数的组合,那get-process和set-content都是函数了,我们又可不可以使用自己定义的函数来接收管道输出呢?of course!
将以下代码拷贝到记事本中并保存为function.ps1为拓展名的文件(.ps1是ps脚本文件的拓展名)
function from-function { foreach($name in $input) { write-host "$name from function" } } filter from-filter { foreach($name in $input) { write-host "$name id from filter"; } }
然后打开ps转到你保存的脚本目录下,输入". ./function.ps1"(注意两个点之间的空格,这种使用脚本的方式称为点源引用,将不会执行脚本而是直接将脚本释放到当前的shell中)
再输入如下命令"get-process|from-function",结果如下图:
你一定注意到了定义函数的同时我还定义了一个filter,在控制台中输入"get-process|from-filter",你将会得到跟上图一样的结果。
那filter跟函数到底有什么不同?$input又是什么?
filter和函数其实是一样的。唯一的不同之处在于filter中的管道对象是一输出即被使用,而函数的管道对象却可以选择在完全输出后才被使用。
让我们在D盘根目录下输入"get-childrenitem -r|from-function"(其中get-childrenitem -r是以递归的方式获得D盘下的所有子项,即获得D盘下的所有文件和文件夹)。如果你D盘的文件数目够多的话你会看到console卡顿的现象,这是因为from-function函数在等待管道对象全部传递完毕储存在$input才开始执行。而输入"get-childrenitem -r|from-filter"你会看见直接执行了。这是因为from-filter这个过滤器在每次管道有对象传入的时候就会执行。
而$input是一个枚举器。可以让函数和过滤器枚举管道对象。他和$_这个变量的作用应该是相同的,至少我还没有发现不同的地方。
其实函数也可以立即输出管道对象而不必等待管道对象接收完毕。将from-function改为:
function from-function { param([string]$hello,[string]world) process { write-host "$input from function" } }
然后再次". ./function.ps1"点源引用脚本以更新当期控制台的from-function函数,输入"get-process|from-function"
你会发现输出的情况和过滤器一样了。注意下面这段话,来自powershell help
“In the Process block of a function, $input contains the object currently in the pipeline… If the function does not have a Process block, the value of $input is
available to the End block, and it contains all of the input to the function.”
原来在函数没有process块的时候,$input将会等待管道对象存储完毕才能使用。而包含process块的时候,$input将包含当前管道对象。而对于后一种情况,建议使用$_而不是$input。过滤器的情况由于与后一种情况相同,所以过滤器中建议使用$_。(我真不知道$input跟$_的区别,谁能告诉我T_T)
最后要说的是,函数中还有Begin{},和End{},这两个脚本块来处理函数的初始化和最后的返回值。不过没有也不会影响函数的运行。你也可以定义函数的参数像下面这样
function from-function { param([string]$hello,[string]$world) process { write-host "$hello $world from function" } }
调用如下命令 get-childrenitem -r|from-function -hello "hello" -world "world",你就可以看见参数传递给函数了。如下图:
函数还用作用域,默认参数等等问题,今天就先到这吧,这些以后有机会再写,dota去了\(^o^)/~