You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell文件分组排序脚本多目录执行不准确问题求助

问题描述

现有PowerShell脚本在网络驱动器的单个测试目录运行完全正常,但修改为在该驱动器的27个目标目录运行时,结果不准确。脚本核心需求是保留最新文件,判断规则如下:

  • 文件未被替代时直接保留;
  • 依据文件名第3-4个下划线间的SECTION段数值判断:文件名格式为NAME_DATE_3位序列_SECTION_SEGMENT_SEQUENCE,比如Name_20240301_001_SectionName_SegmentName_1.pdf和Name_20240301_001_SectionName2_SegmentName_1.pdf,需保留SECTION段数值最大的文件;
  • 同组文件(匹配NAME、DATE、3位序列、SEGMENT及SECTION非数值部分)中的低数值/无数值文件需移至指定检查目录。

该脚本在本地C盘简单结构、网络驱动器2个目录的模拟环境均运行正常,仅在多目录多文件场景下失效。用户疑惑是否需要为每个目录复制脚本逐个执行,或是有递归执行且保证准确性的方法。

原脚本代码
function Get-SectionNumber {
    param([string]$fileName)

    $parts = $fileName -split '_'
    if ($parts.Count -ge 4) {
        $sectionPart = $parts[3]
        $match = [regex]::Match($sectionPart, '(\d+)')
        if ($match.Success) {
            return [int]$match.Value
        }
    }
    return $null
}

function Get-SectionNonNumeric {
    param([string]$fileName)

    $parts = $fileName -split '_'
    if ($parts.Count -ge 4) {
        $sectionPart = $parts[3]
        $match = [regex]::Match($sectionPart, '(\D+)')
        if ($match.Success) {
            return $match.Value
        }
    }
    return $null
}

$sourceDirectory = "Drive:\Path1\Path1......"

$CheckDeletedDirectory = "Drive:\Path2\Path2......"

$files = Get-ChildItem -Path $sourceDirectory -File -Recurse

# portion of the section for grouping
$groupedFiles = $files | Group-Object { ($_.Name -split '_', 4)[0..2] -join '_' + '_' + (Get-SectionNonNumeric $_.Name) }

foreach ($group in $groupedFiles) {

    $sortedGroup = $group.Group | Sort-Object @{Expression={Get-SectionNumber $_.Name}; Descending=$true}

    $topFile = $sortedGroup[0]
    $sortedGroup[1..($sortedGroup.Count - 1)] | ForEach-Object {
        Move-Item -Path $_.FullName -Destination $catchDirectory -Force
        Write-Host "Moved $($file.FullName) to $CheckDeletedDirectory"
    }

       Write-Host "Retained file: $($topFile.FullName)"
}
问题分析与修复方案

1. 原脚本核心问题

  • 变量名错误:Move-Item中使用未定义的$catchDirectory,应为$CheckDeletedDirectory;Write-Host里的$file未定义,需改为$_。
  • 分组逻辑遗漏SEGMENT:原分组仅匹配NAME、DATE、3位序列和SECTION非数值部分,未包含SEGMENT,导致不同SEGMENT的文件被错误归为一组。
  • 递归场景分组冲突:遍历多子目录时,原脚本仅按文件名分组,会跨目录处理文件,不符合实际需求。

2. 修复后的脚本

function Get-SectionInfo {
    param([string]$fileName)
    $parts = $fileName -split '_'
    $sectionNumber = $null
    $sectionNonNumeric = $null
    $segmentPart = $null

    if ($parts.Count -ge 5) {
        # 提取SECTION部分的数值和非数值内容
        $sectionPart = $parts[3]
        $numMatch = [regex]::Match($sectionPart, '(\d+)')
        if ($numMatch.Success) {
            $sectionNumber = [int]$numMatch.Value
        }
        $nonNumMatch = [regex]::Match($sectionPart, '(\D+)')
        if ($nonNumMatch.Success) {
            $sectionNonNumeric = $nonNumMatch.Value
        }
        # 提取SEGMENT部分
        $segmentPart = $parts[4]
    }

    return [PSCustomObject]@{
        SectionNumber = $sectionNumber
        SectionNonNumeric = $sectionNonNumeric
        Segment = $segmentPart
    }
}

# 定义所有27个目标目录
$sourceDirectories = @(
    "Drive:\Path1",
    "Drive:\Path2",
    # 继续添加剩余目录...
)

$CheckDeletedDirectory = "Drive:\Path2\Path2......"

foreach ($dir in $sourceDirectories) {
    if (-not (Test-Path $dir)) {
        Write-Warning "目录不存在:$dir"
        continue
    }

    $files = Get-ChildItem -Path $dir -File

    # 分组键:目录路径 + NAME_DATE_3位序列 + SECTION非数值 + SEGMENT
    $groupedFiles = $files | Group-Object {
        $sectionInfo = Get-SectionInfo $_.Name
        "$($_.Directory.FullName)_$((($_.Name -split '_',4)[0..2]) -join '_')_$($sectionInfo.SectionNonNumeric)_$($sectionInfo.Segment)"
    }

    foreach ($group in $groupedFiles) {
        # 按SectionNumber降序排序,无数值文件默认排最后
        $sortedGroup = $group.Group | Sort-Object @{
            Expression = { $sectionInfo = Get-SectionInfo $_.Name; $sectionInfo.SectionNumber }
            Descending = $true
            Default = 0
        }

        $topFile = $sortedGroup[0]
        Write-Host "保留文件:$($topFile.FullName)"

        # 移动其余文件,处理重名情况
        $sortedGroup[1..($sortedGroup.Count - 1)] | ForEach-Object {
            $targetPath = Join-Path $CheckDeletedDirectory $_.Name
            if (Test-Path $targetPath) {
                $targetPath = Join-Path $CheckDeletedDirectory "$($_.BaseName)_$([guid]::NewGuid().ToString().Substring(0,8))$($_.Extension)"
            }
            Move-Item -Path $_.FullName -Destination $targetPath -Force
            Write-Host "移动文件:$($_.FullName) -> $targetPath"
        }
    }
}

3. 关键优化点

  • 合并SECTION信息提取:将两个提取函数合并,减少重复逻辑,提升效率。
  • 修正分组逻辑:分组时加入目录路径和SEGMENT部分,确保同组文件是同一目录下符合所有规则的文件。
  • 修复变量错误:修正了原脚本中的变量名错误。
  • 处理文件名重复:移动文件时若目标目录有同名文件,自动添加GUID后缀避免覆盖。
  • 批量处理目录:通过数组定义所有目标目录,循环逐个处理,无需复制多份脚本。

内容的提问来源于stack exchange,提问作者Garran Lincoln

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:37:40