PowerShell学习入门 - 4

来源:互联网 发布:天天模拟器官网mac 编辑:程序博客网 时间:2024/05/22 12:52

PowerShell 文件查找test-item 重命名rename-item 文件(夹)路径中的'[' ']'问题

如果你有一个如“委员会会议纪要[2010年10月]-hq.doc”,你怎么得到PowerShell来代替方括号?以下不工作:

ls -filter *`[*`]* | foreach -Process { Rename-Item $_ -NewName ($_.Name -replace '\[', '\(') | Rename-Item $_ -NewName ($_.Name -replace '\]', '\)')}
我得到的错误:
Rename-Item : Cannot rename because item at 'Committee minutes [October 2010] - hq.doc' does not exist.At line:1 char:53+ ls -filter *`[*`]* | foreach -Process { Rename-Item <<<< $_ -NewName ($_.Name -replace '\[']', '\)')} + CategoryInfo   : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException + FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand

列出目录的内容

一般情况下,你可能只想知道在一个确定的目录中有什么文件,如果你不指定其它参数。Dir会列出当前目录的内容。如果你在Dir后跟了一个目录,它的内容也会被列出来,如果你使用了-recurse参数,Dir会列出所有子目录的内容。当然,也允许使用通配符。

例如,你想列出当前目录下的所有PowerShell脚本,输入下面的命令:

1
Dir *.ps1

Dir甚至能支持数组,能让你一次性列出不同驱动器下的内容。下面的命令会同时列出PowerShell根目录下的PowerShell脚本和Windows根目录下的所有日志文件。

1
Dir $pshome\*.ps1, $env:windir\*.log

如果你只对一个目录下的项目名称感兴趣,使用-Name参数,Dir就不会获取对象(Files和directories),只会以纯文本的形式返回它们的名称。

1
Dir -name

注意:一些字符在PowerShell中有特殊的意义,比如方括号。方括号用来访问数组元素的。这也就是为什么使用文件的名称会引起歧义。当你使用-literalPath参数来指定文件的路径时,所有的特殊字符被视为路径片段,PowerShell解释器也不会处理。

解决方法:Dir 默认的参数为-Path。假如你当前文件夹下有个文件名为“.\a[0].txt“,因为方括号是PowerShell中的特殊字符,会解释器被解析。为了能正确获取到”.\a[0].txt”的文件信息,此时可以使用-LiteralPath参数,它会把你传进来的值当作纯文本。

PS> Get-ChildItem .\a[0].txtPS> Get-ChildItem -Path .\a[0].txtPS> Get-ChildItem -LiteralPath .\a[0].txt    Directory: C:\Users\mosserMode                LastWriteTime     Length Name----                -------------     ------ -----a---          2014/1/2     14:04      80370 a[0].txt

递归搜索整个文件系统

当你想搜索整个子目录时,可以使用-recurce参数。但是注意,下面例子执行时会失败。

1
Dir *.ps1 -recurse

你需要了解一点-recurse如何工作的细节来理解为什么会发生上面的情况。Dir总是会获取目录中的内容为文件对象或者目录对象。如果你设置了-recurse开关,Dir会递归遍历目录对象。但是你在上面的例子中使用的通配符只获取扩展名为ps1的文件,没有目录,所以-recurse会跳过。这个概念刚开始使用时可能有点费解,但是下面的使用通配符例子能够递归遍历子目录,正好解释了这点。

在这里,Dir获取了根目录下所有以字母“D”打头的项目。递归开关起了作用,那是因为这些项目中就包含了目录。

1
Dir $home\d* -recurse

荔非苔注:原文的作者写这篇文章时,是基于PowerShell 2.0,在高版本中的PowerShell 中Dir *.ps1 -recurse也是可以工作的。

过滤和排除标准

现在回到刚开始问题,怎样递归列出同类型的所有文件,比如所有PowerShell scripts。答案是使用Dir完全列出所有目录内容,同时指定一个过滤条件。Dir现在可以过滤出你想要列出的文件了。

1
Dir $home -filter *.ps1 -recurse

除了-filter,还有一个参数乍一看和-filter使用起来很像: -include

1
Dir $home -include *.ps1 -recurse

你会看到这一戏剧性的变化,-filter的执行效率明显高于-include:

1
2
3
4
(Measure-Command {Dir $home -filter *.ps1 -recurse}).TotalSeconds
4,6830099
(Measure-Command {Dir $home -include *.ps1 -recurse}).TotalSeconds
28,1017376

其原因在于-include支持正则表达式,从内部实现上就更加复杂,而-filter只支持简单的模式匹配。这也就是为什么你可以使用-include进行更加复杂的过滤。比如下面的例子,搜索所有第一个字符为A-F的脚本文件,显然已经超出了-filter的能力范围。

1
2
3
4
# -filter 查询所有以 "[A-F]"打头的脚本文件,屁都没找到
Dir $home -filter [a-f]*.ps1 -recurse
# -include 能够识别正则表达式,所以可以获取a-f打头,以.ps1收尾的文件
Dir $home -include [a-f]*.ps1 -recurse

与-include相反的是-exclude。在你想排除特定文件时,可以使用-exclude。不像-filter,-include和-exclude还支持数组,能让你获取你的家目录下所有的图片文件。

1
Dir $home -recurse -include *.bmp,*.png,*.jpg, *.gif

做到一点即可:不要混淆了-filter 和 -include。选择这两个参数中的其中一个:具体为当你的过滤条件没有正则表达式时,使用-filter,可以显著提高效率

注意:你不能使用filters在Dir中,列出确定大小的文件列表。因为Dir的限制条件只在文件和目录的名称级别。如果你想使用其它标准来过滤文件,可以尝试第五章中讲到的Where-Object。

下面的例子会获取你家目录下比较大的文件,指定文件至少要100MB大小。

1
Dir $home -recurse Where-Object $_.length -gt 100MB }

如果你想知道Dir返回了多少个文件项,Dir会将结果保存为一个数组,你可以通过数组的的Count属性来读取。下面的命令会告诉你你的家目录下有多少图片文件(这个操作可能会比较耗时)。

获取文件和目录的内容

你可以使用Dir直接获取一个单独的文件,因为Dir会返回一个目录下所有的文件和目录对象。下面的例子会得到这个文件的FileInfo信息:

$file = Dir C:\a.html$file | Format-List *
PSPath            : Microsoft.PowerShell.Core\FileSystem::C:\a.htmlPSParentPath      : Microsoft.PowerShell.Core\FileSystem::C:\PSChildName       : a.htmlPSDrive           : CPSProvider        : Microsoft.PowerShell.Core\FileSystemPSIsContainer     : FalseVersionInfo       : File:             C:\a.html                    InternalName:                    OriginalFilename:                    FileVersion:                    FileDescription:                    Product:                    ProductVersion:                    Debug:            False                    Patched:          False                    PreRelease:       False                    PrivateBuild:     False                    SpecialBuild:     False                    Language:BaseName          : aMode              : -a---Name              : a.htmlLength            : 227740DirectoryName     : C:\Directory         : C:\IsReadOnly        : FalseExists            : TrueFullName          : C:\a.htmlExtension         : .htmlCreationTime      : 2013/11/12 19:29:16CreationTimeUtc   : 2013/11/12 11:29:16LastAccessTime    : 2013/11/12 19:29:16LastAccessTimeUtc : 2013/11/12 11:29:16LastWriteTime     : 2013/11/12 19:29:24LastWriteTimeUtc  : 2013/11/12 11:29:24Attributes        : Archive

你可以访问单个文件的属性,如果它们的属性支持更改,也可以更改。

PS> $file.AttributesArchivePS> $file.Mode-a---

Get-Item是访问单个文件的另外一个途径, 下面的3条命令都会返回同样的结果:你指定的文件的文件对象。

1
2
3
$file = Dir c:\autoexec.bat
$file Get-Childitem c:\autoexec.bat
$file Get-Item c:\autoexec.bat

但是在访问目录而不是文件时,Get-Childitem 和 Get-Item表现迥异。

1
2
3
4
# Dir 或者 Get-Childitem 获取 一个目录下的内容:
$directory = Dir c:\windows
$directory Get-Childitem c:\windows
$directory
    Directory: C:\windowsMode                LastWriteTime     Length Name----                -------------     ------ ----d----         2013/8/22     23:36            addinsd----         2013/8/22     23:36            ADFSd----         2013/8/22     23:36            AppCompatd----        2013/11/22     19:13            apppatchd----        2013/12/27     12:05            AppReadinessd-r--        2013/12/17      3:44            assemblyd----         2013/9/16     10:11            AUInstallAgentd----         2013/8/22     23:36            Bootd----         2013/8/22     23:36            Brandingd----        2013/10/24     14:27            Camera
1
2
3
# Get-Item 获取的是目录对象本身:
$directory Get-Item c:\windows
$directory
    Directory: C:\Mode                LastWriteTime     Length Name----                -------------     ------ ----d----        2013/11/22     19:13            windows
PS> $directory | Format-List *PSPath            : Microsoft.PowerShell.Core\FileSystem::C:\windowsPSParentPath      : Microsoft.PowerShell.Core\FileSystem::C:\PSChildName       : windowsPSDrive           : CPSProvider        : Microsoft.PowerShell.Core\FileSystemPSIsContainer     : TrueBaseName          : windowsMode              : d----Name              : windowsParent            :Exists            : TrueRoot              : C:\FullName          : C:\windowsExtension         :CreationTime      : 2013/8/22 21:36:15CreationTimeUtc   : 2013/8/22 13:36:15LastAccessTime    : 2013/11/22 19:13:22LastAccessTimeUtc : 2013/11/22 11:13:22LastWriteTime     : 2013/11/22 19:13:22LastWriteTimeUtc  : 2013/11/22 11:13:22Attributes        : Directory

向命令,函数和文件脚本传递文件

因为Dir的结果中返回的是独立的文件或目录对象,Dir可以将这些对象直接交付给其它命令或者你自己定义的函数与脚本。这也使得Dir成为了一个非常重要的的选择命令。使用它你可以非常方便地在一个驱动盘下甚至多个驱动盘下递归查找特定类型的所有文件。

要做到这点,在管道中使用Where-Object来处理Dir返回的结果,然后再使用ForEach-Object(第五章),或者你自定义的管道过滤(第九章)。

小知识:你还可以将多个Dir 命令执行的结果结合起来。在下面的例子中,两个分开的Dir命令,产生两个分开的文件列表。然后PowerShell将它们结合起来发送给管道进行深度处理。这个例子获取Windows目录和安装程序目录下的所有的dll文件,然后返回这些dll文件的名称,版本,和描述:

1
2
3
4
5
6
7
8
9
$list1 = Dir $env:windir\system32\*.dll
$list2 = Dir $env:programfiles -recurse -filter *.dll
$totallist $list1 $list2
$totallist ForEach-Object {
$info =
[system.diagnostics.fileversioninfo]::GetVersionInfo($_.FullName);
"{0,-30} {1,15} {2,-20}" -f $_.Name, `
$info.ProductVersion, $info.FileDescription
}
accessibilitycpl.dll            6.3.9600.16384 Ease of access  control panelACCTRES.dll                     6.3.9600.16384 Microsoft Internet Account Manager Resourcesacledit.dll                     6.3.9600.16384 Access Control List Editoraclui.dll                       6.3.9600.16384 Security Descriptor Editoracppage.dll                     6.3.9600.16384 Compatibility Tab Shell Extension Libraryacproxy.dll                     6.3.9600.16384 Autochk Proxy DLLActionCenter.dll                6.3.9600.16384 Action CenterActionCenterCPL.dll             6.3.9600.16384 Action Center Control PanelActionQueue.dll                 6.3.9600.16384 Unattend Action Queue Generator / Executoractiveds.dll                    6.3.9600.16384 ADs Router Layer DLLactxprxy.dll                    6.3.9600.16425 ActiveX Interface Marshaling Libraryadhapi.dll                      6.3.9600.16384 AD harvest sites and subnets APIadhsvc.dll                      6.3.9600.16384 AD Harvest Sites and Subnets Service

因为Dir获取的文件和目录是一样的,有时限制结果中只包含文件或者只包含目录很重要。有很多途径可以做到这点。你可以验证返回对象的属性,PowerShell PSIsContainer属性,或者对象的类型。

1
2
3
4
5
6
7
8
# 只列出目录::
Dir | Where-Object $_ -is [System.IO.DirectoryInfo] }
Dir | Where-Object $_.PSIsContainer }
Dir | Where-Object $_.Mode.Substring(0,1) -eq "d" }
# 只列出文件:
Dir | Where-Object $_ -is [System.IO.FileInfo] }
Dir | Where-Object $_.PSIsContainer -eq $false}
Dir | Where-Object $_.Mode.Substring(0,1) -ne "d" }

前面的例子(识别对象类型)是目前速度最快的,而后面的(文本比较)比较复杂和低效。

Where-Object也可以根据其它属性来过滤。

比如下面的例子通过管道过滤2007年5月12日后更改过的文件:

1
Dir | Where-Object $_.CreationTime -gt [datetime]::Parse("May 12, 2007") }

也可以使用相对时间获取2周以内更改过的文件:

1
Dir | Where-Object $_.CreationTime -gt (Get-Date).AddDays(-14) }

原文地址:Working with the File System




0 0
原创粉丝点击