zoukankan      html  css  js  c++  java
  • PowerShell: 管道对象

    PowerShell的管道不同于传统的基于文本的管道,而是基于对象的管道。

    PowerShell中有类流水线操作,它要求任何命令cmdlet以一个满足要求且标准接口的.NET对象出现。建立在.NET之上的特性允许Shell传递.NET对象,而不是文本。这样不再需要生成文本,不必从其他程序中传递文本。管道不再是文本流,而是各种对象的集合,这些对象可以很容易地向外界展现其包含的任何属性、方法等信息。

    (1) ForEach-Object:简写为“foreach”,允许操作管道中的任意项,结果是包含所有操作返回值的集合。用于处理集合。

    PowerShell提供了用操作符多次操作集合的语言特性,ForEach-Object命令通过对每个对象和集合运用相同的操作而使重复代码最小化,并返回新的集合。

    最简单的情况下,ForEach-Object至少需要两个输入,一是集合,通常由上一个命令传送;二是操作,操作以脚本块的形式来表现。

    PS C:\> dir

    Directory: Microsoft.PowerShell.Core\FileSystem::C:\l

    Mode LastWriteTime Length Name

    ---- ------------- ------ ----

    -a--- 1/17/2009 11:33 PM 4 test.txt

    -a--- 1/17/2007 11:34 PM 12 test2.txt

    -a--- 1/17/2007 11:33 PM 4 test3.txt

    -a--- 1/17/2007 11:34 PM 14 test4.txt

    PS C:\> dir | ForEach-Object { $_.Length }

    4

    12

    4

    14

    $_是个很特殊的变量,它保存一个到当前对象的索引,如同在JavaScript中的this。ForEach-Object将循环作用于所有的对象,用$_变量来代替当前的对象,并调用脚本块。

    通常当循环操作开始之前需要进行初始化,操作所有的对象后需要给出结果。开发人员可以通过传递两个脚本块作为begin和end。下例遍历当前目录所有的文件,这里用一个累加计数器置零为开始。在循环体中增加文件数目,并且最后显示和:

    PS C:\> dir | ForEach-Object –begin{$sum=0} –process `

    {$sum +=$_.Length} –end {echo “Total size of files: $sum bytes.”}

    Total size of files: 34 bytes.

    process参数是默认的,尽管很多时候并不是必须的。但是使用begin和end脚本块时,包含process将会使得命令更加的易读。

    (2) Where-Object:与where及?相互为别名,过滤集合并返回符合条件的项。命名空间来自于数据库中SQL字句,用特定条件来过滤数据表内容。用于过滤集合。

    内置的cmdlet提供了很多功能,以Get-Process为例,它将会返回所有进程并允许通过使用进程名来过滤未发生的进程。为了能获取所有占用内存超过20 MB的进程:可以将Get-Process的输出作为Where-Object的输入。where需要的参数包括集合及脚本块。脚本块将会在所有的对象上执行,只有返回值为$true的对象将会被包含在结果集合当中。具体的实例如下:

    PS C:\> Get-Process | Where-Object {$_.WS –ge 20MB}

    Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

    ------- ------ ----- ----- ----- ------ -- -----------

    156 8 99296 58544 191 134.00 2808 dwm

    847 39 59112 58472 277 99.48 2852 explorer

    431 11 65792 53012 157 1004 svchost

    328 17 21780 48908 297 23.19 2600 WINWORD

    WS属性的别名为“WorkingSet”,返回进程在当前所占用物理内存的量,-ge是greater-than-or-equal比较操作符。

    (3) Select-Object:简写为“select”,用于创建包含原始对象属性子集的对象集合,这个命名空间也来自SQL语言,SELECT操作用来定义将表中的哪些列取回。

    用于新增或删除指定对象的属性。

    Select-Object对应于数据库中的select,用于定义在检索中返回的列。Where-Object允许在对象中选择属性的子集,也可以选择表格的列。同样Select-Objectcmdlet允许从结果对象集中移除属性,甚至在其中新增新的属性。

    在最简单的情况下,Select-Object要求一个被返回的属性列表。下例只提取当前文件夹中文件的文件名和最后访问时间:

    PS C:\> dir | Select-Object Name,LastAccessTime

    Name LastAccessTime

    ------ -----------------

    test.txt 1/17/2009 8:55:12 AM

    test2.txt 1/17/2009 8:55:12 AM

    test3.txt 1/17/2009 8:55:12 AM

    test4.txt 1/17/2009 8:55:12 AM

    为对象增加属性也是类似的方法,它遵循这样的规定,即定义一个可计算的属性并传递包含属性名的字典及可计算属性的表达式。下例为文件列表增加LastAccessWeekDay属性:

    PS C:\> dir | Select-Object Name,

    @{Name=”LastAccessWeekDay”;Expression=

    {$_.LastAccessTime.DayOfWeek}}

    Name LastAccessWeekDa

    ------ -----------------

    test.txt Saturday

    test2.txt Saturday

    test3.txt Saturday

    test4.txt Saturday

    需要注意的是Select-Object也可以使用$_来替代当前的对象。

    值得一提的是Select-Object具有一种很方便的用法,可以用传递first和last参数选择最前面或是最后面的N列。下例使用这种方法来选择当前文件夹中前面或后面的两个文件:

    PS C:\> dir *.txt | select –first 2

    Directory: Microsoft.PowerShell.Core\FileSystem::C:\PowerShell

    Mode LastWriteTime Length Name

    ---- ------------- ------ ----

    -a--- 1/17/2009 11:33 PM 4 other.txt

    -a--- 1/17/2009 11:34 PM 7 test.txt

    PS C:\> dir *.txt | select –last 2

    Directory: Microsoft.PowerShell.Core\FileSystem::C:\PowerShell

    Mode LastWriteTime Length Name

    ---- ------------- ------ ----

    -a--- 1/17/2009 11:36 PM 12 test4.txt

    -a--- 1/17/2009 11:35 PM 14 test3.txt

    如果对象是被排序的,则获取前面或后面几个对象非常有用。这将允许开发人员很容易获取集合中感兴趣的对象,如获取最大的5个文件,或消耗内存最多的3个进程等。

    (4) Sort-Object:简写为“sort”,有别于基础排序的常见操作,可以按照一个或多个属性排序集合并支持高级的选项。

    如果要根据一些属性值来排序数据,则在PowerShell中通过Sort-Object实现。用户要做的只是为cmdlet传递一个属性列表,Sort-Object自动将集合排序。下例按照占用的内存大小排序进程列表:

    PS C:\> Get-Process | Sort-Object WS

    Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

    ------- ------ ----- ----- ----- ------ -- -----------

    0 0 0 16 0 0 Idle

    28 1 248 524 4 364 smss

    713 0 0 532 4 4 System

    ...

    347 18 22524 49612 312 34.55 2600 WINWORD

    431 11 66084 53300 157 1004 svchost

    848 39 59116 58532 277 101.20 2852 explorer

    如果要某个降序排列属性,则传递-descending参数即可,如:

    PS C:\> Get-Process | Sort-Object WS –descending

    Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

    ------- ------ ----- ----- ----- ------ -- -----------

    848 39 59116 58532 277 101.20 2852 explorer

    431 11 66084 53300 157 1004 svchost

    347 18 22524 49612 312 34.55 2600 WINWORD

    ...

    713 0 0 532 4 4 System

    28 1 248 524 4 364 smss

    0 0 0 16 0 0 Idle

    (5) 管道树

    Tee-Object:简写为“tee”,在把集合传递给下一个命令之前保存当前管道到文件或变量。可以在管道执行的特定阶段保存集合,并在后面的命令中使用这个集合。

    建立长命令管道是表示复杂操作的有效方法,有时需要获取在管道命令中生成的对象并保存以备后面使用。更常见的情况是在操作对象之前需要存储一系列的对象,如要终止一系列进程,但需要在结束进程之前将进程名写入日志文件中。通常会使用Get-Process和Stop-Process来获取和终止进程:

    PS C:\>Get-Process notepad | Stop-Process

    PS C:\>

    为了把Get-Process获取到的对象写入文件中,需要在管道中使用Tee-Object cmdlet:

    PS C:\>Get-Process notepad | Tee-Object –file kill.log |Stop-Process

    PS C:\>type kill.log

    Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

    ------- ------ ----- ----- ----- ------ -- -----------

    50 2 1200 4076 54 1.48 2772 notepad

    48 2 1200 4016 54 0.77 2880 notepad

    有时并不需要写入磁盘,而将变量作为中间媒介来存储,只需要将-file参数换成-variable参数:

    PS C:\>Get-Process notepad | Tee-Object –variable KilledProcesses |Stop-Process

    PS C:\>$KilledProcesses

    Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

    ------- ------ ----- ----- ----- ------ -- -----------

    48 2 1204 4016 54 0.23 3876 notepad

    48 2 1200 4052 54 0.48 3884 notepad

    PS C:\> $KilledProcesses |select ProcessName,WS,HasExited

    ProcessName WS(K) HasExited

    ----------- ------- ---------

    notepad 4016 True

    notepad 4052 True

    需要注意的是不必在Tee-Object –variable中的变量前面加美元符($)的前缀,只需要传递变量名。cmdlet定义变量并设置其值,即在使用变量之前需要定义。这里只是传递变量名,并不需要用户定义度量,而是PowerShell外壳自动完成。

    (6) Group-Object:简写为“group”,把对象集合按照属性值分为多个分组。

    很多处理对象的过程中需要将对换分成多个分类,PowerShell使用Group-Object的cmdlet使分类操作变得简单。最常见的情况是根据某项属性值来分类集合,下例根据系统服务的状态将其分类:

    PS C:\> Get-Service | Group-Object Status

    Count Name Group

    ----- ---- -----

    50 Running

    {System.ServiceProcess.ServiceController,

    System.ServiceProcess.ServiceController, S...

    60 Stopped

    {System.ServiceProcess.ServiceController,

    System.ServiceProcess.ServiceController, S...

    结果是GroupInfo对象的集合。可以通过访问GroupInfo的Group属性可以逐个获取和查询属于分类的实际对象,如:

    PS C:\> (Get-Service | Group-Object Status)[1].Group

    Status Name DisplayName

    ------ ---- -----------

    Stopped ALG Application Layer Gateway Service

    Stopped Appinfo Application Information

    Stopped AppMgmt Application Management

    Stopped AudioEndpointBu... Windows Audio Endpoint Builder

    Stopped Audiosrv Windows Audio

    Stopped Browser Computer Browser

    ……

    前面的实例用来展示所有状态为“Stopped”的系统服务分类。如果要获取所有启动的系统服务,只需要将索引值1换为0即可获取启动的服务组。需要强调的是前例中的圆括号结束管道命令并将结果作为包含集合的常规变量。

    (7) Measure-Object:计算集合的统计值,提供一个简便的方法来获取最小值、最大值及平均值属性。

    通常,如果需要收集大量对象的统计信息,则需要逐个遍历所有对象,为此使用Measure-Object这个cmdlet。使用这个cmdlet能用最少的代码量来遍历整个集合并计算属性值中最常见的统计信息,如计数、求和、最小值、最大值及平均值。下例收集与所有文件大小相关的信息:

    PS C:\>dir –r | Measure-Object –property Length –min –max –average -sum

    Count : 39963

    Average : 164494.456822561

    Sum : 6573691978

    Maximum : 136491745

    Minimum : 0

    Property : Length

    该例使用dir命令的-r参数来实现递归遍历所有的文件,查询每个文件的长度属性并计算出统计信息。有趣的是Measure-Object完全可以通过为ForEach-Object命令设置合理的参数来替代它,为了方便,一般情况下最好使用Measure-Object,而将ForEach-Object留在更复杂的情况下使用。

    (8) Compare-Object:简写为“diff”,用于比较两个对象或集合并报告其不同。

    所有的脚本语言都会遇上比较两个对象或集合的任务,即是否有相应的对象被增加或删除。PowerShell的Compare-Object会遍历两个对象,并报告之间的不同。传统的diff工具基于文本,而Compare-Object面向对象。下例用其来检测当前的文件夹和昨天备份之间的不同:

    PS C:\> diff (dir .\PowerShellBackup) (dir .\PowerShell)

    InputObject SideIndicator

    ----------- -------------

    kill.log =>

    单侧指示器(side Indicator)=>符号代表两个文件夹中不同的对象kill.log对象是存在于右侧的集合中。与此对应,存在<=符号表示两个集合中存在差异的对象仅在左侧存在。

    Compare-Object帮助用户创建强大的脚本,如可以将其输出导入到ForEach-Object而创建简单的备份更新脚本,将新创建的文件从PowerShell文件夹中复制到PowerShellBackup文件夹中。从一个目录中复制所有文件到另外一个目录是个很危险的操作,为了确保没有因覆盖而丢失重要文件,下例传递了-confirm参数给copy命令:

    PS C:\> diff (dir PowerShellBackup) (dir PowerShell) | `

    >> where {$_.SideIndicator -eq "=>"} | `

    >> ForEach {copy -confirm "PowerShell\$($_.InputObject)" `

    >> "PowerShellBackup"}

    >>

    Confirm

    Are you sure you want to perform this action?

    Performing operation "Copy File" on Target "Item:

    C:\PowerShell\kill.log Destination:

    C:\PowerShellBackup\kill.log".

    [Y] Yes [A] Yes to All [N] No

    [L] No to All [S] Suspend

    [?] Help (default is "Y"): y

    需要强调的是这里首先过滤了diff的结果,仅保留了单侧指示器为=>的对象,最后使用了$_.InputObject的值来代替要复制的文件路径。

    参考资料:http://www.qqread.com/other-devtool/j493909.html

  • 相关阅读:
    蓝桥杯之递归算法基本框架

    Dubbo是什么
    java
    java
    java
    java
    java
    负载均衡的理解
    设计模式学习
  • 原文地址:https://www.cnblogs.com/ITGirlXiaoXiao/p/2119760.html
Copyright © 2011-2022 走看看