引子正则表达式
一直很羡慕Linux的命令提示符(固然他们叫Shell)。正则表达式,管道,各类神奇的命令,组合起来就能高效完成不少复杂的任务。效率实在是高。流了n年的哈喇子之后,终于有幸用上了Win7,邂逅了cmd的升级版:Windows PowerShell。今后暗爽无比,原来Windows下也有这样的利器呀~
看看下面的Windows脚本,不到15行有效代码。在Win7下只要右击脚本文件,选择Run with PowerShell,就会自动找到最占内存的10个进程,而后将它们占用的内存画成一个三维饼图,以下图所示。shell
# create new excel instance
$objExcel = New-Object -comobject Excel.Application
$objExcel.Visible = $True
$objWorkbook = $objExcel.Workbooks.Add()
$objWorksheet = $objWorkbook.Worksheets.Item(1)
# write information to the excel file
$i = 0
$first10 = (ps | sort ws -Descending | select -first 10)
$first10 | foreach -Process {$i++; $objWorksheet.Cells.Item($i,1) = $_.name; $objWorksheet.Cells.Item($i,2) = $_.ws}
$otherMem = (ps | measure ws -s).Sum - ($first10 | measure ws -s).Sum
$objWorksheet.Cells.Item(11,1) = "Others"; $objWorksheet.Cells.Item(11,2) = $otherMemwindows
# draw the pie chart
$objCharts = $objWorksheet.ChartObjects()
$objChart = $objCharts.Add(0, 0, 500, 300)
$objChart.Chart.SetSourceData($objWorksheet.range("A1:B11"), 2)
$objChart.Chart.ChartType = 70
$objChart.Chart.ApplyDataLabels(5)数组
(1. 这个脚本调用了Excel的COM库。 2. 固然从命令耦合的角度来看,输出成文本格式更有利,但这个例子主要想说明PowerShell的强大以及微软产品优异的复用性。 3. 要手动启动PowerShell,能够在开始菜单的搜索框中直接键入PowerShell回车便可)
简单领略PowerShell的强大以后,下文就从几个方面介绍一下PowerShell相对于以往版本的命令提示符甚至Linux Shell的优点。网络
Cmdlet + Regex + Pipeline + ...数据结构
以往cmd相对于Shell有不少不足,好比命令偏少,部分命令功能偏弱,对正则表达式不支持等等。但如今PowerShell一下遇上来很多。2.0 RTM版内建支持414个命令(术语称为cmdlet),支持正则表达式,强大的管道应用(其实管道自己的功能和之前差很少,关键是冒出来一堆能用管道的命令,好比more, sort, foreach等等),和系统的联系也比之前紧密了不少。异步
举几个例子来讲明:函数
dir registry::HKEY_CURRENT_USER能够直接显示注册表相应位置的内容,能够看到dir的功能改进了很多。工具
ps | sort ws -Descending | select -first 10能够显示占用内存最大的10个进程,能够看到管道的灵活应用。spa
dir -Name | ? {$_ -match "(?<num>.).*(\k<num>)"}能够显示出当前目录下文件名有重复字符的文件。好比abcda.efg,而abcd.efg则不会显示出来。能够看到PowerShell对正则表达式的支持至关强大。(确切的说严格的正则表达式 已经没法实现这样的效果,须要上下文无关文法 才可以支持。)
之前为了演示Linux Shell的强大,Stephenjy发了一个本身的截图,在碰见PowerShell前以为好神奇,所幸如今也能够实现了。:-)
(为了节约显示空间,PowerShell的部分显示结果被删除,但这个Prompt效果能够用如下脚本验证: function prompt {"($env:username)-($env:computername)-(`$?: $?)-(jobs: $((get-job | measure).Count))-($(get-location))`n(! $(((history)[-1]).ID + 1))->"})
大杀器 - 面向对象
Linux的设计思想决定全部的输入和输出都尽量是文本格式,这样能够方便各进程间的合做。一样这也要求各个程序提供必定强度的文本解析能力。但Windows的思想与此不一样,PowerShell中不少输入输出都不是普通的文本(plain text),而是一个个对象(objects)。所以与其说PowerShell是一种交互环境,不如说它是一种强大语言的Runtime,而这种语言甚至是面向对象的。
好比当键入get-process查看当前进程列表时,系统返回的是这样的列表:
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
318 8 12948 3872 84 1728 AppleMobileD
115 5 13816 13328 38 6920 audiodg
1315 21 11732 10988 108 2544 CcmExec
... ...
虽然看似通常的格式化文本,但其实这是一个数组,而每一个数组元素又是Process类型的对象。同.NET一脉相承,PowerShell中的全部的类都继承自Object,且支持GetType()函数。所以咱们能够执行(get-process).GetType()来看看它的类型:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
而数组中每一个元素的类型能够用(get-process)[0].GetType()查看:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False Process System.ComponentM...
其中面向思想的思想很是明显,类成员,方法,继承都出现了。我的感受这样的好处并非期望能用PowerShell写什么大型软件,而是体如今另外两个方面:首先,这样让内置的cmdlet及其数据结构组织清晰,符合直觉,写代码时速度快不容易出错。第二,对面向对象的内建支持也为后面无缝接合.NET和COM接口提供了基础。
站在巨人的肩膀上 - 无缝调用.NET/COM
.NET Framework中包含了一个异常强大的库,而微软为了保证二进制层面上跨语言的兼容性,不少库都是用COM封装的。PowerShell的一大特点就是能够直接调用这些库。好比前面的示例用$objExcel = New-Object -comobject Excel.Application建立了一个Excel对象。而wikipedia上的一个脚本更示范了这种无缝调用的强大。下面这个3句话的脚本的做用是显示一个RSS源最近的8篇文章的标题。注意其中网络链接,内容下载,XML解析等工做所有由.NET库完成,正由于站在巨人的肩膀上,PowerShell在实际使用中每每左右逢源,简洁高效。
$rssUrl = "http://blogs.msdn.com/powershell/rss.aspx"
$blog = [xml](new-object System.Net.WebClient).DownloadString($rssUrl)
$blog.rss.channel.item | select title -first 8
编辑,运行,调试 - IDE
Windows程序开发,尤为是基于微软技术的开发很爽的一点就是有强大的IDE和专业的文档做支持。不管是Windows下的Visual Studio仍是Linux下的Mono Develop,甚至连PowerShell这样的语言都有集编辑与调试为一体的IDE:Windows PowerShell ISE。有了自动完成,即时脚本交互,调试甚至远程调试,PowerShell脚本写起来“甚爽甚强巨”。固然文档也是通常的强大,MSDN中关于PowerShell的部分依旧专业浩瀚。
蛋疼的假装 - Profile
有了PowerShell之后,不多就去cmd了。不过做为一个蛋疼的装B男,把PowerShell假装成cmd也是挺有乐趣的一件事。不难发现PowerShell和cmd仅仅在图标,标题,背景色,提示符,以及刚启动时的显示文字五个方面不一样。图标和背景色在快捷方式属性中能够很方便的修改。而标题和提示符的修改就要用到Profile了。所谓Profile就是在每次启动PowerShell时都首先自动运行的一段脚本。这个脚本的路径在$profile变量中有设定。只要设定$host.UI.RawUI.WindowTitle为C:\windows\system32\cmd.exe就能将标题假装为cmd。而自定义提示符为当前路径在PowerShell中天然万分简单。至于启动时的显示文字,只要经过/nologo参数隐藏原有的版本信息,再打印一行cmd中的文字就行了。最终效果如图:(关于Profile,能够参见这个连接)
另:进程级工做调度 – 并行支持?
==========================================================
随着多核处理器的迅速发展,从.NET Framework 4.0开始,并行计算被一再强调。从System.Threading中新增长的并行工具类到F#这种很是适合并行化的函数式语言,微软适时对线程级并行提供了强大的支持。可是对于进程级的工做调度,Windows彷佛还至关原始。举个最简单的例子来讲,若是咱们同时向一个移动硬盘启动5个拷贝会话的话,Windows会同时开始全部的拷贝操做。这样磁头会在不一样的目标位置间反复进行无心义的移动(寻道),因而在硬盘灯的狂闪中,大量时间就被浪费了。一样当咱们同时启动数个计算量大的进程时,Windows也会试图让这些进程“齐头并进”。然而为了不某个进程被饿死,系统又不得不频繁切换进程,因而大量的时间又被浪费在了保存现场,进程切换,恢复现场上。这样来看,进程级的并行作的反而不够好。
所幸PowerShell中加入了任务调度管理功能。经过简单的实验,咱们能够发现PowerShell对jobs的调度和Windows默认的大不相同,它通常维持和CPU核心数相同的进程高速运转,而其它进程仅仅占用小部分CPU时间。直到前面的进程结束工做后,后面才有新的进程递补进入高速运转的状态。==========================================================后来更仔细地作了实验之后发现,原来Windows内置的进程调度方案就是小部分高速运转(在个人双核处理器上是两个进程占用50%CPU),大部分低速跟进(其余全部进程分享剩下的50%CPU)。这样PowerShell的工做调度并无改善系统原有的现状。同时因为PowerShell的调度系统须要占用不小的内存,初始化也须要时间。在实测中甚至比默认调度慢了50%。这个实验结果比较囧。不晓得为何PowerShell中为何要加入Job这个东西,难道仅仅为了异步调用吗?