【问题标题】:PowerShell: Copy/Move Files based on a regex value, retaining the folder structure, etcPowerShell:根据正则表达式值复制/移动文件,保留文件夹结构等
【发布时间】:2011-10-25 18:18:33
【问题描述】:

场景如下:我们有一个生产网络服务器,其中包含数千个文件和文件夹,这些文件和文件夹附加了一个“_DATE”。我们想将它们移动到一个临时文件夹(确保它们没有被使用),并在以后删除这些文件。

我可以使用:

Get-ChildItem -Path W:\IIS -Recurse | Where-Object{$_.Name -match "_\d{8,10}$"}

获取所有文件/文件夹及其位置的列表。但是手动删除它们似乎需要做很多工作,特别是如果将来需要这样做。我找到了一些几乎可以满足我要求的示例:

cls

$source = "W:\IIS"
$destination = "C:\Temp\DevTest" 

foreach ($i in Get-ChildItem -Path $source -Recurse)
{
    if ($i.Name -match "_\d{8,10}$")
    {
        Copy-Item -Path $i.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Trim($item.Name)
    }
}

还有:

cls

$source = "W:\IIS"
$destination = "C:\Temp\DevTest" 

$bin = Get-ChildItem -Path $source -Recurse | Where-Object{$_.Name -match "_\d{8,10}$"}

foreach ($item in $bin) {
    Copy-Item -Path $item.FullName -Container -Destination $item.FullName.ToString().Replace($source,$destination).Trim($item.Name) -Recurse
}

这两个的问题是,当我只用 copy-item 测试它们时,我最终会得到一个平面目录,我需要保留目录结构,以便如果移动出错我可以恢复(最好通过拖动和将所有文件夹放回 IIS 文件夹中),否则我会得到许多额外文件夹/文件的副本,这些文件夹/文件在我运行第一个命令时不会出现。

将我的第一个命令修改为:

Get-ChildItem -Path W:\IIS -Recurse | Where-Object{$_.Name -match "_\d{8,10}$"} | Copy-Item -Container -Destination C:\Temp\DevTest -Recurse

将复制我需要的所有内容,但使用平面目录树,而不是保留树结构(但用目标替换源目录)。

有什么建议/cmets?

【问题讨论】:

    标签: regex powershell web


    【解决方案1】:

    理想情况下,第一个应该可以工作。它确实保留了目录结构。但是你必须小心复制文件夹。假设您只想要您想要的模式中的文件并且您不关心那里的文件夹,您可以执行以下操作:

    $source = "W:\IIS"
    $destination = "C:\Temp\DevTest" 
    
    if(-not (Test-Path $destination)) { mkdir $destination | out-null}
    
    foreach ($i in Get-ChildItem -Path $source -Recurse)
    {
        if (($i.Name -notmatch "_\d{8,10}$") -and (-not $i.PsIsContainer))
        {
            continue;
        }
        Copy-Item -Path $i.FullName -Destination $i.FullName.Replace($source,$destination).Trim($i.Name)
    }
    

    【讨论】:

    • +1 你的代码(解释)比我的更清楚,但我把它建在桌子的角落里。
    • @666jfox777 - 你是什么意思没有拿起正则表达式?
    • @manojlds 它复制了几乎每个文件夹,而不仅仅是我所追求的文件夹,我最终得到了许多与正则表达式不匹配的额外空目录 (_\d{8,10}$)。
    • 好的,所以您没有阅读我的回答中的Assuming you want just the files in the pattern that you want in and you don't care about the folders being there 行。那么当文件夹名称不匹配但文件夹中的文件匹配时会发生什么?
    【解决方案2】:

    您可以尝试以下方法,这似乎可以完成工作(尽管它可以使用一些重构)。核心是ProcessFolder(…),它被递归调用。

    function Log
    {
        param($Error)
        if(!$script:log)
        {
            $script:log = join-path $dst "log$timestamp.txt"
        }
        $timestamp
        $timestamp >> $script:log
        $Error
        $Error >> $script:log
    }
    
    function CopyFile
    {
        param($Path)
        $tmp = join-path $dst $Path.Substring($src.Length)
        write-host "File src: $Path"
        write-host "File dst: $tmp"
        Try
        {
            #copy the file
            copy $Path $tmp -Force
        }
        Catch
        {
            Log "ERROR copying file $Path to $tmp`:`
            $_"
        }
    }
    
    function ProcessFolder
    {
        param($Path)
        $tmp = join-path $dst $Path.Substring($src.Length)
        write-host "Dir. src: $Path"
        write-host "Dir. dst: $tmp"
        Try
        {
            #create target directory
            New-Item $tmp -itemtype directory -force > $null
            #process files if they match
            dir $Path | ?{!$_.PsIsContainer -and $_.Name -match "_\d{8,10}$" } | sort | %{ CopyFile $_.FullName }
            #process subdirectories
            dir $Path | ?{$_.PsIsContainer} | sort | %{ ProcessFolder $_.FullName }
            #remove target directory if it contains no files on any level
            if( !(dir $tmp -recurse | ?{!$_.PsIsContainer}) ) { del $tmp -recurse }
        }
        Catch
        {
            Log "ERROR copying folder $Path to $tmp`:`
            $_"
        }
    }
    
    cls
    
    $src = "W:\IIS\"
    $dst = "C:\Temp\DevTest\"
    $log = $null
    $timestamp = '{0:yyyyMMddHHmmssfffffff}' -f (Get-Date)
    ProcessFolder $src
    
    ''
    'DONE!'
    if( $log )
    {
        echo "Check the log file: $log"
    }
    Read-Host
    

    【讨论】:

    【解决方案3】:

    对我来说 Copy-Item 是一团糟,您可以阅读其他 StackOverflow 答案 this onethis other one 。这是一种“拼凑”的解决方案。

    $source = "W:\\IIS" # Really double \
    
    Get-ChildItem -Path $source -Recurse | Where-Object{($_.Name -match ""_\d{8,10}$") -or ($_.psiscontainer)} | % {copy-item  $_.fullname ($_.fullname -replace $source,'C:\Temp\DevTest') }
    

    【讨论】:

      【解决方案4】:

      有了这个,你甚至可以复制奇怪的 Windows 路径,比如“Program Files (x86)” 也可用于 any 路径正则表达式匹配。这个是用于文明VI /Text/提取的;-)

      Clear-Host
      
      $source = "C:\Program Files (x86)\Steam\steamapps\common\Sid Meier's Civilization VI"
      $dest = "C:\Tmp\Civ"
      $match = ".*\\Text\\.*" # RegExp for match
      
      $_DEBUG = $true
      
      $sourceReg = [regex]::Escape($source)
      
      if ($_DEBUG) {$sourceReg}
      
      Get-ChildItem -Path $source -Recurse | Where-Object{($_.FullName -match $match)} |
          % {
              if ($_DEBUG) {$_.fullname  + ": " + ($_.fullname -replace $sourceReg, $dest) }
              copy-item  $_.fullname ($_.fullname -replace $sourceReg, $dest) -Recurse -Force 
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-22
        • 2021-02-26
        • 1970-01-01
        • 1970-01-01
        • 2019-11-27
        • 1970-01-01
        相关资源
        最近更新 更多