欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Windows PowerShell是啥?看完本文你就懂它了

程序员文章站 2024-01-01 21:58:22
引子 一直很羡慕linux的命令提示符(当然他们叫shell)。正则表达式,管道,各种神奇的命令,组合起来就能高效完成很多复杂的任务。效率实在是高。流了n年的哈喇子以后,...

引子

一直很羡慕linux的命令提示符(当然他们叫shell)。正则表达式,管道,各种神奇的命令,组合起来就能高效完成很多复杂的任务。效率实在是高。流了n年的哈喇子以后,终于有幸用上了win7,邂逅了cmd的升级版:windows powershell。从此暗爽无比,原来windows下也有这样的利器呀~
看看下面的windows脚本,不到15行有效代码。在win7下只要右击脚本文件,选择run with powershell,就会自动找到最占内存的10个进程,然后将它们占用的内存画成一个三维饼图,如下图所示。

Windows PowerShell是啥?看完本文你就懂它了

复制代码 代码如下:

# 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) = $othermem

# 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的优势。

Windows PowerShell是啥?看完本文你就懂它了

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个进程,可以看到管道的灵活应用。

dir -name | ? {$_ -match "(?<num>.).*(\k<num>)"}可以显示出当前目录下文件名有重复字符的文件。比如abcda.efg,而abcd.efg则不会显示出来。可以看到powershell对正则表达式的支持相当强大。(确切的说严格的正则表达式 已经无法实现这样的效果,需要上下文无关文法 才能够支持。)
以前为了演示linux shell的强大,stephenjy发了一个自己的截图,在遇见powershell前觉得好神奇,所幸现在也可以实现了。:-)

Windows PowerShell是啥?看完本文你就懂它了

Windows 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的部分依旧专业浩瀚。

Windows 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,可以参见这个链接

Windows PowerShell是啥?看完本文你就懂它了

另:进程级工作调度 – 并行支持?

==========================================================
随着多核处理器的迅速发展,从.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这个东西,难道仅仅为了异步调用吗?

上一篇:

下一篇: