PowerShell:根据正则表达式值复制/移动文件,保留文件夹结构等

时间:2011-10-25 18:18:33

标签: regex powershell web

这是一个场景:我们有一个生产Web服务器,它有几千个附加了“_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

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

有任何建议/意见吗?

4 个答案:

答案 0 :(得分:2)

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

$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 :(得分:1)

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

$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') }

答案 2 :(得分:1)

您可以使用以下内容,这似乎可以完成工作(虽然它可以使用一些重构)。核心是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 :(得分:0)

使用此命令,您甚至可以复制怪异的Windows路径,例如“ Program Files(x86)”。 也可用于 any 路径正则表达式匹配。这个用于文明VI /文本/提取;-)

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 
    }