ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

PowerShell笔记 - 4.管道

2021-09-13 12:34:16  阅读:171  来源: 互联网

标签:PS Name Format 对象 Object 笔记 ---- 管道 PowerShell


本系列是一个重新学习PowerShell的笔记,内容引用自PowerShell中文博客

使用管道

排序导并导出JSON格式文件

PS C:\Code> ls | Sort-Object -Descending Name | Select-Object -First 1 Name,Length,LastWriteTime | ConvertTo-Json | Out-File ls.txt                                                                                                             PS C:\Code> Get-Content .\ls.txt
{
    "Name":  "Redis",
    "Length":  null,
    "LastWriteTime":  "\/Date(1623377222092)\/"
}
首先列出当前目录下的目录和文件,然后根据文件名降序排列,再投影文件名,文件大小,文件的修改时间,转换成Html格式,输出到当前目录的ls.txt

面向对象的管道

上面的例子属于面向对象的管道,每个命令的末尾可以使用新的命令对上个命令的结果做进一步处理,除非管道是以输出命令结束的。就像Sort-Object一样,对文件的列表进行排序,需要告诉它排序的关键字,按照升序还是降序。ls的返回值为一个数组,数组中的每一个元素都是一个对象,对象的每一个属性都可以作为Sort-Object的排序关键字。但是排序时必须指定一个具体的关键字,因为Powershell所传递的对象可能有很多属性。不像普通的文本,对象的信息都是结构化的,因此也使得Powershell的管道变得更加强大和方便。

转换命令执行的结果为文本

在执行Powershell命令时,解释器会默认在命令的结尾追加一个管道命令,Out-Default,这样可以将原来的对象结果以文本的形式显示在控制台上,但是并没有将结果进行转换,所以可以继续使用其它管道对对象的结果进行操作,但是一旦使用了诸如ConvertTo-JSON这样的命令后,就会将结果转换成固定格式的纯文本。

常用管道命令

    #常用的对管道结果进一步处理的命令有:
    Compare-Object: 比较两组对象。
    ConvertTo-Html: 将 Microsoft .NET Framework 对象转换为可在 Web 浏览器中显示的 HTML。
    Export-Clixml: 创建对象的基于 XML 的表示形式并将其存储在文件中。
    Export-Csv: 将 Microsoft .NET Framework 对象转换为一系列以逗号分隔的、长度可变的 (CSV) 字符串,并将这些字符串保存到一个 CSV 文件中。
    ForEach-Object: 针对每一组输入对象执行操作。
    Format-List: 将输出的格式设置为属性列表,其中每个属性均各占一行显示。
    Format-Table: 将输出的格式设置为表。
    Format-Wide: 将对象的格式设置为只能显示每个对象的一个属性的宽表。
    Get-Unique: 从排序列表返回唯一项目。
    Group-Object: 指定的属性包含相同值的组对象。
    Import-Clixml: 导入 CLIXML 文件,并在 Windows PowerShell 中创建相应的对象。
    Measure-Object: 计算对象的数字属性以及字符串对象(如文本文件)中的字符数、单词数和行数。
    more: 对结果分屏显示。
    Out-File: 将输出发送到文件。
    Out-Null: 删除输出,不将其发送到控制台。
    Out-Printer: 将输出发送到打印机。
    Out-String: 将对象作为一列字符串发送到主机。
    Select-Object: 选择一个对象或一组对象的指定属性。它还可以从对象的数组中选择唯一对象,也可以从对象数组的开头或末尾选择指定个数的对象。
    Sort-Object: 按属性值对象进行排序。
    Tee-Object: 将命令输出保存在文件或变量中,并将其显示在控制台中。
    Where-Object: 创建控制哪些对象沿着命令管道传递的筛选器。

管道的处理模式

当我们把许多命名组合成一个管道时,可能会感兴趣每一个命令的执行时是顺序执行还是同时执行?通过管道处理结果实际上是实时的。这就是为什么存在两个管道模式:

顺序模式(较慢)
在顺序模式中管道中同一时间只执行一条命令,只有当前一条命令的所有执行完毕,才会把所有结果交付给下一条 命令。这种模式速度慢并且耗内存,因为必须需要很多次分配空间存储中间结果。
流模式(较快)
流模式会立即执行所有命令,同一时间可能在执行多条命令。前一条命令可能会产生多个结果,但是一旦产生其中一个结果,就会立即交付给下一条命令处理。这样的流模式节省比较节省内存,可能管道的某个任务还在执行,但是已经有部分结果输出了。减少了中间结果的保存。

管道命令的阻塞

可以使用Sort-Object对管道的结果进行排序,但是有时候排序可能导致整个操作系统阻塞,因为排序命令的的执行属于顺序模式,必须得上一条命令的结果全部完成,才能排序。
因此在使用这类命令时,要注意操作对象的大小,和它们需要的内存。例如这条命令:
Dir C: -recurse | Sort-Object -recurse 选项是递归查询子目录,可想而知系统盘的文件和目录有多大。
这条命令一旦运行起来,需要等很长很长的时间,甚至可能导致系统崩溃,得重启电脑。
你可以在执行这条命令时,打开任务管理器查看Powershell进程的内存占用在以每秒种几十兆的速率增加。
到底哪些命令可能系统阻塞,要视命令的实现方式以及处理的对象大小决定,例如Sort-object导致阻塞的原因肯定是由于技术实现上采用的是内排序,没有使用外排序。
但是象Out-Host -paging 这样的命令属于流出来模式,就一般不会导致系统阻塞。

将对象转换为文本

怎样将Powershell的对象结果转换成文本并显示在控制台上。Powershell已经内置Out-Default命令追加在管道的命令串的末尾。因此你使用dir 和dir | out-default的结果是相同的。
Out-Default可以将对象转换成可视的文本。事实上Out-Default会首先调用Format-Table,将更多的属性默认隐藏。再调用Out-Host将结果输出在控制台上。因此下面的四组命令执行结果是相同的。
PS C:\Code> ls                                                                                                  PS C:\Code> ls | Format-Table                                                                                   PS C:\Code> ls | Format-Table | Out-Default                                                                     PS C:\Code> ls | Format-Table | Out-Default |Out-Host  

#显示隐藏的对象属性
PS C:\Code\testdir> ls | Format-Table *

#使用通配符显示进程的名字和其它以”pe”打头,以”64″结尾的进程。
PS C:\Code> Get-Process i* | Format-Table Name,pe*64                                                                                                                                         
Name                                PeakPagedMemorySize64 PeakWorkingSet64 PeakVirtualMemorySize64
----                                --------------------- ---------------- -----------------------
ibmpmsvc                                          2994176          9728000              4404154368
Idle                                                61440            12288                    8192
igfxCUIService                                    3088384         12537856           2203426746368

#添加定义列
PS C:\Code> ls | Format-Table Name,{ [int]($_.Length/1kb) }                                                                                                                                  
Name                   [int]($_.Length/1kb)
----                  ----------------------
0605                                       0
0707                                       0
0811                                       0
0917                                       0
1020                                       0
1201                                       0

#定义列头
PS C:\Code> $column = @{Expression={ [int]($_.Length/1KB) }; Label="KB" }                                                                                                                    PS C:\Code> ls | Format-Table Name,$column                                                                                                                                                   
Name                  KB
----                  --
0605                   0
0707                   0
0811                   0
0917                   0

排序及分组

#分组
PS C:\Code> ls | Group-Object Extension |Format-Table Name,Count                                                                                                                             
Name  Count
----  -----
         18
.xlsx     1
.txt      1

#排序
PS C:\Code> ls | Group-Object Extension |Sort-Object @{expression="Count";Descending=$true},@{expression="Name";Ascending=$true} |Format-Table Name,Count                                    
Name  Count
----  -----
         18
.txt      1
.xlsx     1

分析和对比

使用Measure-Object和Compare-Object可以统计和对比管道结果。
Measure-Object允许指定待统计对象的属性。Compare-Object可以对比对象前后的快照。

统计和计算

#统计
PS C:\Code> ls | Measure-Object Length                                                                                  

Count    : 2 #文件数量
Average  :
Sum      :
Maximum  :
Minimum  :
Property : Length

#指定统计最大最小等
PS C:\Code> ls | Measure-Object Length -Average -Sum -Maximum -Minimum

Count    : 2
Average  : 6566
Sum      : 13132
Maximum  : 12930
Minimum  : 202
Property : Length

#统计文本文件内的行、字、词等
PS C:\Code> Get-Content .\ls.txt | Measure-Object -Line -Word -Character

Lines Words Characters Property
----- ----- ---------- --------
    5     8         90

对比

PS C:\Code> $d1 = Get-Date
PS C:\Code> $d2 = Get-Date
PS C:\Code> Compare-Object $d1 $d2

InputObject        SideIndicator
-----------        -------------
2021/9/10 17:45:50 => #新增项
2021/9/10 17:45:36 <= #删除项

#指定属性对比
PS C:\Code> $h1 = @{N=1}
PS C:\Code> $h2 = @{N=2}
PS C:\Code> Compare-Object $h1 $h2 -Property Values

Values SideIndicator
------ -------------
{2}    =>
{1}    <=

PS C:\Code> Compare-Object $h1 $h2 -Property Keys

扩展类型系统

Powershell一个最吸引人的功能是它能够将任何对象转换成文本,我们已经使用过将对象属性以不同的版式转换成文本,并且输出。更令人惊奇的是Powershell会把最重要最能代表这个对象本质的信息输出。一个对象有很多属性,为什么它单单就输出那几个属性呢?
如下:

PS C:\> dir | Select-Object -First 1 | Format-Table *  -Wrap
PSPath  PSParentPath    PSChildName     PSDrive
------

Powershell会最大限度的输出每个属性,但是这样的输出基本上没有意义,不利于用户阅读。那到底是什么让Powershell默认只显示此属性不显示彼属性呢?
是“扩展类型系统”Extended Type System (ETS),ETS会对管道中对象转换成文本的机制进行宏观调控。
ETS由两部分组成,一部分控制对象的版式,一部分控制对象的属性,今天主要关心第一部分。

文本转换不可逆

在管道中将对象结果转换成文本后,不能再将文本转换成对象,因为ETS不能处理文本。
如果通过ConvertTo-String将目录列表的转换成String后,使用Format-Table和Format-List这些命令就会无效。

PS C:> $test = Dir |Out-String                                                                                                                                                    PS C:> $test                                                                                                                                                                      

    Directory: C:


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        2021/6/10     14:40                8001
d-----        2021/6/11     10:12                8002
d-----        2021/6/11     10:12                8003

PS C:> $test | Format-List


    Directory: C:

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        2021/6/10     14:40                8001
d-----        2021/6/11     10:12                8002
d-----        2021/6/11     10:12                8003


PS C:> dir | Format-List                                                                                                                                                          

    Directory: C:

Name           : 8001
CreationTime   : 2021/6/10 13:43:27
LastWriteTime  : 2021/6/10 14:40:50
LastAccessTime : 2021/6/10 14:40:50
Mode           : d-----
LinkType       :
Target         : {}

已知对象格式化

如果使用了格式化的命令,但是没有指定具体的属性(如: dir | Format-Table)。ETS将会首次大展拳脚,它会决定那些对象应当显示,那些属性应当被自动选择。ETS在做这些工作之前,首先应当弄清楚,那些对象能够被转换成文本。

PS C:> (Dir)[0].GetType().FullName                                                                                                                                                System.IO.DirectoryInfo

Dir 返回一个System.IO.DirectoryInfo对象,并且包含了这个对象里面的System.IO.FileInfo对象和System.IO.DirectoryInfo子对象。这样ETS就可以去检查自己的内部记录,通过内部记录的配置,将对象转换成文本。这些内部记录为XML文件,扩展名为“.ps1xml”

PS C:> dir $PSHOME *format.ps1*                                                                                                                                                   

    Directory: C:\Windows\System32\WindowsPowerShell\v1.0


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2019/3/19     12:46          12825 Certificate.format.ps1xml
-a----        2019/3/19     12:46           5074 Diagnostics.Format.ps1xml
-a----        2019/3/19     12:46         138223 DotNetTypes.format.ps1xml
-a----        2019/3/19     12:46          10144 Event.Format.ps1xml
-a----        2019/3/19     12:46          25526 FileSystem.format.ps1xml
-a----        2019/3/19     12:46          91655 Help.format.ps1xml
-a----        2019/3/19     12:46         138625 HelpV3.format.ps1xml
-a----        2019/3/19     12:46         206468 PowerShellCore.format.ps1xml
-a----        2019/3/19     12:46           4097 PowerShellTrace.format.ps1xml
-a----        2019/3/19     12:46           8458 Registry.format.ps1xml
-a----        2019/3/19     12:46          16598 WSMan.Format.ps1xml

每一个对象详细地被定义在这些XML文件中,定义包括那些对象属性支持转换成文本,那些对象应当默认显示在列表或者表格中。
有一点之前说过,对于一行上面的混合命令“ Get-Process ; dir”ETS不支持,要想避免最好的方式是每个命令明确地指定版式。

PS C:> Get-Process | Format-Table ; dir | Format-Table

未知对象格式化

在ps1xml中定义过的对象属于已知对象,那些未知对象ETS应当怎样处理呢?
对于未知对象,ETS遵循一个规律: 如果对象的属性少于5个则表格显示,否则列表显示。
下面的例子创建一个对象,并向对象中逐个增加属性。

PS C:> $obj = New-Object psobject                                                                            PS C:> Add-Member -MemberType NoteProperty -Name "A" -Value "1" -InputObject $obj                            PS C:> $obj                                                                                                  
A
-
1


PS C:> Add-Member -MemberType NoteProperty -Name "B" -Value "2" -InputObject $obj                            PS C:> Add-Member -MemberType NoteProperty -Name "C" -Value "3" -InputObject $obj                            PS C:> $obj                                                                                                  
A B C
- - -
1 2 3


PS C:> Add-Member -MemberType NoteProperty -Name "D" -Value "4" -InputObject $obj                            PS C:> Add-Member -MemberType NoteProperty -Name "E" -Value "5" -InputObject $obj                            PS C:> $obj                                                                                                  

A : 1
B : 2
C : 3
D : 4
E : 5

应急模式

如果ETS从输出中发现临界状态,会自动切换到列表显示。例如“Get-Process; Dir”,ETS正在以表格形式输出Process对象,但是突然碰到一个FileInfo对象,就会直接切换到列表模式,输出其它类型的对象。

隐藏列

如果碰到未知的对象,ETS会试着从管道输出的第一个结果寻找线索,这样可能导致一个奇怪的现象。ETS会根据未知对象的第一个结果,来判断属性,但第一条结果的属性并不总会输出。可能再碰到包含更多属性的对象时,当前选择的属性信息就可能会被抑制。
接下来的例子演示那些信息会被抑制,Get-Process 返回正在运行的所有进程,然后通过StartTime进行排序,最输出每个进程的名称和开启时间:

PS C:> Get-Process | Sort-Object StartTime | Select-Object Name                                              Sort-Object : Exception getting "StartTime": "Access is denied"
At line:1 char:15
+ Get-Process | Sort-Object StartTime | Select-Object Name
+               ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidResult: (System.Diagnostics.Process (1E.Client):PSObject) [Sort-Object], GetValue
   InvocationException
    + FullyQualifiedErrorId : ExpressionEvaluation,Microsoft.PowerShell.Commands.SortObjectCommand

当执行上面的命令行时,会收到许多错误信息。这些错误信息并不是来源于命令,而是可能因为当前控制台没有管理员权限,某些系统进程拒绝访问。输出的进程中可能有一部分进程只有进程名(Name),没有开启时间(StartTime),开启时间被抑制了。
使用Select-Object,会删除对象的某些属性,但是对象本身的属性是不能删除的,所以ETS会在管道中重新生成一个对象,类型为:System.Management.Automation.PSCustomObject。

PS C:> Get-Process | foreach{$_.GetType().FullName} | Select-Object -First 1                                 System.Diagnostics.Process
PS C:> (Get-Process | foreach{$_.GetType().FullName} | Select-Object -First 1 Name).GetType().FullName       System.Management.Automation.PSCustomObject

因为PSCustomObject在ETS配置中没有记录,就会输出全部属性。
管道结果之前根据StartTime升序排列过,所以前面的进程由于权限问题没有StartTime。

标签:PS,Name,Format,对象,Object,笔记,----,管道,PowerShell
来源: https://www.cnblogs.com/MerLin-LiuNian/p/15261930.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有