如何在PowerShell对象中存储文件列表?

时间:2015-07-24 10:46:36

标签: powershell

我有这段代码:

$filestowatch=get-content C:\GT\files-to-watch.txt
$adminFiles=dir C:\GT\admin\src\admin\wwwroot\content\less\ |? {$filestowatch -contains $_.Name}
$userfiles=dir  C:\GT\user-staging\src\user_staging\wwwroot\content\less\|? {$filestowatch -contains $_.Name}

并在files-to-watch.txt

_dark.less
_light.less

这将创建一个adminFiles列表和我的代码使用的userFiles列表。

但是我有一个问题,一些文件在wwwroot下的目录中。所以我需要在这里观看文件:

\content\less\_dark.less
\content\less\_light.less
\lib\abc.txt
\index.txt

有人可以提供帮助并建议我如何更改此代码以便它可以使用目录,然后使用files-to-watch.txt中的文件名。

更新 - 这是我提出的完整代码,我尝试了vesper的建议,但似乎无法使用我的代码。

$filestowatch=get-content C:\GT\files-to-watch.txt

$adminFiles=dir C:\GT\admin\src\admin\wwwroot -recurse | 
    ? { $fn=$_.FullName; ($filestowatch | % {$fn.contains($_)}) -contains $True}

$userFiles=dir C:\GT\user-staging\src\user-staging\wwwroot -recurse | 
    ? { $fn=$_.FullName; ($filestowatch | % {$fn.contains($_)}) -contains $True}

foreach($userfile in $userFiles)
{
   Write-Host "Checking" $userfile.FullName 

      $exactadminfile= $adminfiles | ? {$_.Name -eq $userfile.Name} |Select -First 1
      $filetext1=[System.IO.File]::ReadAllText($exactadminfile.FullName)
      $filetext2=[System.IO.File]::ReadAllText($userfile.FullName)
      $equal = $filetext1 -ceq $filetext2 # case sensitive comparison

      if ($equal) { break; }

      if($exactadminfile.LastWriteTime -gt $userfile.LastWriteTime)
      {
         Write-Host "Copying  $exactadminfile.FullName to $userfile.FullName "
         Copy-Item -Path $exactadminfile.FullName -Destination $userfile.FullName -Force
       }
       else
       {
          Write-Host "Copying  $userfile.FullName to $exactadminfile.FullName "
          Copy-Item -Path $userfile.FullName -Destination $exactadminfile.FullName -Force
       }
}

和我要观看的文件

content\less\_dark.less
content\less\_light.less

我认为这很接近,但它给了我这个错误:

PS C:\Windows\system32> C:\GT\watcher.ps1
dir : Cannot find path 'C:\GT\user-staging\src\user-staging\' because it does not exist.
At C:\GT\watcher.ps1:8 char:12
+ $userFiles=dir C:\GT\user-staging\src\user-staging\wwwroot -recurse |
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\GT\user-staging\src\user-staging\:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

2 个答案:

答案 0 :(得分:2)

您需要针对包含部分路径的数组过滤$_.FullName。比如说,您的$filestowatch包含您列出的值。然后,您使用this trick快速生成$_.FullName中的“任意匹配”过滤器:

$adminFiles=dir C:\GT\admin\src\admin\wwwroot -recurse | 
    ? { $fn=$_.FullName; ($filestowatch | % {$fn.contains($_)}) -contains $True}

这对$filestowatch运行一个子字符串检查,生成一组布尔值,如果其中任何一个是$True,则匹配,Where-Object过滤器传递找到的{ {1}}通过管道对象。

答案 1 :(得分:2)

我将文件和文件夹路径分解为变量,这使得测试和可读性变得更加容易。当然,您可以随意改变。就像Vesper一样,如果你担心父目录中的文件,你需要使用-recurse。我所听到的不同之处在于创建了一个从文本文件中的路径构建的正则表达式字符串。此外,我通过将两个调用的输出组合到Get-ChildItem

来应用过滤器一次
$adminfilePath = "C:\GT\admin\src\admin\wwwroot"
$userfilePath = "C:\GT\user-staging\src\user_staging\wwwroot"
$filesToWatchPath = "C:\GT\files-to-watch.txt"

$filter = (Get-Content $filesToWatchPath | ForEach-Object{[regex]::Escape($_)}) -join "|"
$adminFiles = @(Get-ChildItem $adminfilePath  -Recurse | Select-Object -ExpandProperty FullName)
$userfiles = @(Get-ChildItem $userfilePath -Recurse | Select-Object -ExpandProperty FullName)

$adminFiles + $userfiles | Where-Object{$_ -match $filter}

使用示例文本,我们创建一个类似于

的过滤器
_dark\.less|_light\.less

使用[regex]::Escape()我们可以转义任何可能出现在字符串中的正则表达式控制字符,如句点。我们使用-join来创建匹配组。