zoukankan      html  css  js  c++  java
  • Windows PowerShell 2.0之输入输出

    由程序生成的数据通常会比生成它的程序有更长的存活期,文本文件能够很容易地从一个系统传输到另一个系统。本文将探讨PowerShell操作文件的机制、如何读取不同的数据格式并生成自己的数据,以及如何使用正则表达式从文本块中获取数据。

    1 读取内容

    在PowerShell中,Get-Content和Set-Content这两个cmdlet分别用于获取和设置原始二进制文件。默认情况下,这两个命令用于操作文本文件。图1所示为使用Get-Content获取文件内容。

    clip_image002

    图1 使用Get-Content获取文件内容

    Get-Content以行为单位返回一个字符串数组,每个数组元素中包含一行内容。图2所示为返回5个元素的字符串数组的文件内容。

    clip_image004

    图2 通过Get-Content返回以5个元素的字符串数组的文件内容

    从图中可以看到,返回值为数组形式。如果操作的文件内容为每行一个条目存在,则使得记录操作非常方便。

    如果需要获取整个文件内容并转换为一个独立的字符串形式,则使用[string]::Join()静态方法。这个方法将字符串数组用分隔符连接为单个字符串,这里的分隔符为换行符。不同系统会使用不同的字符来作为换行符,如Windows使用回车换行符(在PowerShell中使用`r`n作为转义字符),在Unix系统中使用换行符(`r),苹果机上使用回车符(`n)。当前PowerShell仅应用在Windows系统中,可以使用`r`n作为换行的分隔符。但是最好从系统中获取分隔符,如果将来PowerShell在其他操作系统中有相应的解释引擎,则现在编写的所有脚本均可在其中无障碍地应用。从.NET环境中获取换行符需要访问静态属性[System.Envoironment]::NewLine。

    下面创建一个通用脚本Get-ContentAsString.ps1,以字符串形式读取文件内容:

    Param($Path)

    $lines = Get-Content -Path $Path

    $newLine = [System.Environment]::NewLine

    $content = [String]::Join($newLine,$lines)

    $content

    图3所示为使用上述脚本读取infoOfPeople.txt文件并检查其中返回值的方法。

    clip_image006

    图3 使用Get-Content以字符串形式读取文件的方法

    在读取的文件中包含52个字符,其中前7个字符用换行符分隔组成字符串“Sun WuK”。

    Get-Content能够同时从多个文件中获取文本,当为Get-Content传递的对象是文件集合时,则返回所有的文件内容,内容是经过合并后的文件内容。图4所示为使用这个cmdlet获取当前目录中所有*.txt文件的内容,在获取之前列出目录。可以看到当前目录下有两个txt文件,分别是前面演示的实例文件infoOfPeople.txt和test.txt。

    clip_image008

    图4 使用Get-Content获取当前目录中所有*.txt文件的内容

    也可以通过传递通配符给Get-Content读取同样的内容,如图5所示。

    clip_image010

    图5 向Get-Content传递通配符读取多个文件

    由于前面创建的Get-ContentAsString.ps1是基于Get-Content的功能封装的,所以它具有Get-Content的所有属性,为其传递通配符给参数$Path的结果如图6所示。

    clip_image012

    图6 为Get-ContentAsString.ps1传递通配符给参数$Path的结果

    前面使用Get-Content获取的是字符串的集合,这里返回的是单一的字符串。为了验证二者的不同,构造两个如图7所示的表达式。

    clip_image014

    图7 两个表达式

    2 写入内容

    Set-Content的-Value参数指定要写入文件的对象(另一个-Path参数指定保存文件的路径),可以用管道输出代替。如果指定的参数是对象,则会调用其中内置的ToString()方法转换为字符串保存到文件中;如果指定的是集合,则会枚举其中的所有成员并分别赋值给单独的对象。图8所示为将两个文件的内容写入到一个文件中。

    clip_image016

    图8 用Set-Content转换对象将两个文件的内容写入到一个文件中

    能够看到从dir命令获取的FileInfo对象用其中内置的ToString()方法返回了文件的全路径。

    需要注意的是Set-Content具有破坏性,如果要写入的文件已经存在,则将被新写入的内容覆盖。所以在使用Set-Content之前一定要确认目标路径是否存在同名文件,如果存在,则确认文件是否覆盖;否则将会丢失原有数据。

    要在已有文件尾添加新的内容,需要使用到Add-Content这个cmdlet,其参数与Set-Content相同。图9所示为使用Add-Content在texts.txt尾添加新的内容。

    clip_image018

    图9 使用Add-Content在texts.txt尾添加新的内容

    上例中直接将dir命令的输出用管道传递给Add-Content,相当于将dir命令的输出赋值给-Value参数并执行Add-Content操作。

    PowerShell支持两种输出重定向操作符,允许用户将命令输出保存在文件中。>操作符将会传递当前对象给文件并覆盖其原有文件的内容,示例如图10所示。

    clip_image020

    图10 使用>输出重定向操作覆盖文件原有文件内容的示例

    >>操作符的功能与>类似,但它在原有文件尾添加新的内容,其示例如图11所示。

    clip_image022

    图11 使用>>在原有文件尾添加新内容的示例

    能够看到>和>>操作符的功能分别与Set-Content和Add-Content类似,不同在于重定向操作将输入对象用管道传递给PowerShell的格式化机制,而Set-Content和Add-Content用其本身具有的ToString()方法。

    3 指定编码方式

    计算机首选的文字格式如美国信息交换标准码(ASCII)只是适用于用单字节标识字符,从而限制了能够表达的字符数量。这种编码只是用于标识拉丁字符,而对于其他字符,如古斯拉夫文字、希伯来文字、阿拉伯文字、中文、日文和韩文等则无能为力;这就是Unicode标准化组织要制定新的一套文字编码标准来表示所有字符集的原因。

    Get-Content和Set-Content这类cmdlet支持通过使用-Encoding参数指定编码方式来读写文件,该参数的取值如下。

    (1)Unkonwn:未指定编码方式,默认为Unicode编码方式。

    (2)String:内容作为Unicode字符串处理,等同于Unicode编码方式。

    (3)Unicode:在.NET框架和PowerShell中将字节顺序(endianness)为低地址存放最低有效字节的16位的Unicode编码作为默认字符串格式(这里的字节顺序Little Endian取决于底层硬件架构采用Intel的x86系列CPU,如果采用Motorola的PowerPC系列CPU,则使用Big Endian方式,即低地址存放最高有效字节。请参阅相关文档),本章后面将会详细介绍不同字节顺序下的Unicode编码方式。

    (4)Byte:返回字节数组,适用于以二进制形式读写一个文件。

    (5)BigEndianUnicode:类似Unicode,但是使用Big Endian字节顺序。

    (6)UTF8:使用Unicode统一编码标准的UTF-8编码方式。

    (7)UTF7:使用Unicode统一编码标准的UTF-7编码方式。

    (8)Ascii:每字符使用8位ASCII编码返回文件内容,仅用于英文字符。

    其中的常用值是Byte、Unicode、UTF8和Ascii。

    3.1 获取二进制内容

    操作文件的有效方法是字节数组方式,这种方式允许用户修改文件中的任何的内容。图12所示为ASCII方式写字符串序列到文件中,然后以字节方式读出。

    clip_image024

    图12 用不同编码方式读写文件

    这里将字符串序列“aaaabbb”以特定编码方式写入到文件中,当以字节方式读出文件内容后显示的内容分别是4个a和3个b的ASCII码值,即添加了两个原来并未写入的ASCII值分别为10(回车)和13(换行)的字符。这两个字符由Set-Content自动添加,以标识文件结束。

    【提示】

    Set-Content自动添加换行符对于文本文件的影响可能并不明显,但是如果需要文件内容无换行,则需要注意,唯一能够避免Set-Content自动添加换行符的方法是使用字节(Byte)编码方式并以字节数组的形式赋值文件内容。

    当需要以十六进制形式显示字节值时会经常操作字节,另外所有关于二进制数据文件的操作均使用十六进制处理。下面创建一个名为“Format-AsHex.ps1”的脚本,使用-f字符串格式化操作符格式化所有用管道传递的数字,代码如下:

    process

    {

    "{0:X}" -f $_

    }

    使用这个脚本处理之后的ASCII数据如图13所示。

    clip_image026

    图13 结果之后的数据

    可以看到十六进制的a是61,b是62,回车符是D,换行符是A。

    3.2 不同Unicode编码

    本节将使用不同编码保存文件,然后使用工具来查看二进制数据,这样即可看到.NET中不同编码之间的关系。首先从.NET标准的Unicode编码开始,保存字符串序列到文件中并读出,执行结果如图14所示。

    clip_image028

    图14 执行结果

    根据标准,Unicode格式的文本文件始于由字节顺序唯一标识的字节序列,称为“字节顺序标志”(Byte Order Mark,BOM)。BOM是必要的,因为有些系统使用两个字节表示一个数据,如字符“A”的码值以0061的形式表示,如同正常的数学符号;另一种情况反转了字节的顺序,将其表示为6100,这两种表示方式分别称为“Big Endian”和“Little Endian”。基于Intel系列CPU和.NET框架均使用后者,在.NET中称为“采用Unicode编码”。与此相对应的方式是Big Endian Unicode,文件开始包含的BOM的内容是FFFE。

    下面查看相同序列如何采用Big Endian Unicode编码方式,以及其中的如何组织字节,如图15所示。

    BOM中包含FEFF,字符“A”被表示为0061。

    clip_image030

    图15 采用Big Endian Unicode编码方式

    Unicode和Big Endian Unicode编码使用两个字节编码每个字符,从而在表示英文字符时不可避免地浪费一个字节。UTF-8的编码使用一个字节编码一个英文字符,使用两个或多个字节编码其他语言字符解决这个问题。图16所示为采用UTF8编码方式保存文件。

    clip_image032

    图16 采用UTF8编码方式

    这样缩短了文件长度,在aaabb之前添加的3位称为“UTF-8的BOM序列”。UTF-8格式不存在顺序问题,但是需要指定BOM序列,这样程序可以用其检测文本文件是否使用UTF-8编码。

    【提示】

    UTF-8的BOM的3个符号曾在网页和文本文件中出现过,即。EFBBBF这个序列是个可印刷字符,不知道如何处理UTF-8编码的程序通常将其显示给用户。

    下面编写一个名为“Detect-Encoding.ps1”的脚本读取文件开始的前3个字节,并与已知的BOM标志值比较。如果匹配某种特征,则输出相应的编码名;否则作为ASCII文件来处理。其代码如下:

    param ($Path)

    $start = Get-Content -Path $Path -Encoding Byte -TotalCount 3

    $utf8BOM = "{0:X}{1:X}{2:X}" -f $start

    $utf16BOM = "{0:X}{1:X}" -f $start

    if ($uft8BOM -eq "EFBBBF")

    {

    Write-Host "UTF-8"

    exit

    }

    if ($uft16BOM -eq "FFFE")

    {

    Write-Host "Unicode"

    exit

    }

    if ($uft16BOM -eq "FEFF")

    {

    Write-Host "Big Endian Unicode"

    exit

    }

    Write-Host "No BOM detected. Encoding is most likely ASCII."

    代码中为Get-Content传递了-TotalCount参数,以仅提取前3个字节,然后将其格式化为十六进制并检测序列是否满足UTF8的BOM。如果不满足,则格式化前两个字节并分别与Unicode和Big Endian Unicode的BOM序列比较。图17所示为检测之前生成的文本文件的编码方式。

    clip_image034

    图17 检测之前生成的文本文件的编码方式

    【提示】

    Unicode协会的主页地址是http://www.unicode.org/,其中包含完整的Unicode标准的规范。该标准针对主题分别定义,所以非常冗长,不易阅读。言简意赅且浅显易懂地介绍文字编码主题的文章可以在Joel Spolsky的文章“The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)”中看到,这篇文章可以在http://www.joelonsoftware.com/articles/Unicode.html网页中找到。需要为读者介绍的另外一种编程方面的技能就是要学会如何通过Internet找到前人已经总结的经验和规律,这些经验和规律可能浅显易懂。但是如果由读者自己来验证,则有一定难度。可以在他人的基础上学习,这样才能以最小的代价最快地达成目标。

    4 从文本中提取数据

    一般情况下很难分割和提取文本文件中包含的数据,这是因为其中包含一定数量的空格或其他分隔符。使用正则表达式可以快速定位到目标字符串,并提出相应的内容。

    【提示】

    关于正则表达式的更多信息可以访问在线资源http://www.regular-expressions.inf,其中涵盖了多种语言和环境中正则表达式的使用方法。有关.NET正则表达式内容的在线资源可访问http://www.regular-expressions.info/dotnet.html。尽管正则表达式在各个平台上或多或少有些相似,但是在不同的语言中有很多细微的差别,在使用正则表达式之前需要仔细核对表达式和语言种类是否匹配。

    4.1 查找符合正则表达式的匹配

    通过指定\d+为正则表达式来描述一个数字,这意味着“一个或多个数字符号”。调用正则表达式的Matches()方法将返回一个匹配对象的集合,可以通过检测每个匹配中的Success属性来判断匹配成功与否。如果成功,则可以通过第1个Group对象的Value属性得到匹配成功的具体值。下面创建一个名为“Extract-Numbers.ps1”的脚本,代码如下:

    $nums = .\Get-ContentAsString.ps1 .\test_numbers.txt

    $numberMatcher = [regex] "\d+"

    $matches = $numberMatcher.Matches($nums)

    foreach ($match in $matches)

    {

    if ($match.Success)

    {

    $number = $match.Groups[0].Value

    Write-Host "number:$number"

    }

    }

    需要强调的是第1个组的下标从索引0开始,图18所示为执行结果。

    clip_image036

    图18 执行结果

    该脚本中操作的文本文件只要包含数字,即可过滤。

    4.2 查找文件中的字符串

    PowerShell中的Select-String是一个内置cmdlet,用其可以查找文件中的字符串或满足特定正则表达式的记录。熟悉Unix的读者可以使用grep的工具,在Windows下则可以使用findstr工具。

    Select-String的参数-Pattern用于指定要查找的字符串或满足特定正则表达式的记录,-Path参数指定要查找的文件名或通配符。为了验证这个cmdlet的功能,搜索当前目录中所有包含“if”字符串的脚本文件,如图19所示。

    clip_image038

    图19 使用Select-String搜索当前目录中所有包含“if”字符串的脚本文件

    获取的结果是一个MatchInfo的对象集合,其中包含发现匹配存在的文件和行数信息,图20所示为获取的信息行、文件名和路径。

    clip_image040

    图20 获取的信息行、文件名和路径

    正则表达式是个非常有用的工具,尽管存在一定的复杂性,但是对于以后高效使用PowerShell很有帮助。而且一旦掌握了某门语言的正则表达式,则很容易掌握其他语言的正则表达式。

    5 总 结

    本文探讨了PowerShell操作文件的机制、如何读取不同的数据格式并生成自己的数据,以及如何使用正则表达式从文本块中获取数据。说明了如何操作文件,包括引用、处理和保存文件等。并且说明了可以在不同平台之间转换文件的常见字符编码,以及如何使用正则表达式提取文本文件中的内容。

    作者: 付海军
    出处:http://fuhj02.cnblogs.com
    版权:本文版权归作者和博客园共有
    转载:欢迎转载,为了保存作者的创作热情,请按要求【转载】,谢谢
    要求:未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
    个人网站: http://txj.shell.tor.hu/

  • 相关阅读:
    JavaScript基础知识-流程控制之for循环
    JavaScript基础知识-流程控制之while循环
    HAProxy的高级配置选项-基于cookie实现的session保持实战案例
    HAProxy的四层与七层的区别及透传IP实战案例
    HAProxy基础配置-haproxy常见的调度算法
    HAProxy基础配置-配置haproxy的日志
    HAProxy基础配置-配置多进程多线程案例
    HAProxy基础配置-修改haproxy运行时的用户身份
    HAProxy基础配置-基于http的反向代理
    HAProxy基础配置-haproxy的配置文件说明
  • 原文地址:https://www.cnblogs.com/fuhj02/p/1910943.html
Copyright © 2011-2022 走看看