【问题标题】:Find specific files by date modified and copy to the relevant folder按修改日期查找特定文件并复制到相关文件夹
【发布时间】:2018-01-28 08:55:43
【问题描述】:

我正在寻找一个 PowerShell 脚本,它可以从源目录中找到文件(N30008xx.txtN30005xx.txt),并通过创建与文件修改日期同名的文件夹将它们复制到目标目录。

我可以运行以下脚本,该脚本按文件修改日期创建文件夹。

$p = "Filesourcepath"

Get-ChildItem -Path $p |
    Where-Object { ! ($_.PSIsContainer) } | 
    ForEach-Object {
        $newDir = Join-Path $p ($_.LastWriteTime).ToString("yyyy-MM-dd")
        New-Item -Path $newDir -ItemType Directory -ErrorAction SilentlyContinue
        $_ | Move-Item -Destination $newDir
    }

【问题讨论】:

  • 如果你想复制一些你不应该移动的东西。

标签: powershell


【解决方案1】:

您的代码应该在原则上工作。 (在撰写本文时,复制移动存在混淆,并且缺少仅匹配选定文件的方面。)

以下是您的代码的简化版本,但是,不能解释您的症状 - 您需要为我们提供更多信息诊断您的问题。


下面的精简代码:

  • 利用 PSv3+ -File Get-ChildItem 参数来限制对文件(而不是目录)的匹配 - 这节省了@ 987654324@.

  • 使用-LiteralPath 传递文字$dir 路径;虽然-Path(也是位置默认值)通常也可以正常工作,但重要的是要注意它会将 is 参数解释为 通配符表达式,这可能会产生意想不到的结果)。

  • 使用-Filter 提供文件掩码(通配符表达式);这通常比使用 -Path 参数更可取,因为它在源(Windows API 调用)进行过滤,因此速度更快,这在处理大型目录时会产生显着差异。
    警告-Filter 参数中支持的通配符语言比 PowerShell 更受限制,并且还带有遗留的怪癖;简而言之:坚持使用*? 应该没问题;完整故事请见this well-researched answer

  • 使用-Force 而不是-ErrorAction SilentlyContinue 来创建目录或使用预先存在的目录。

    • 请注意,New-Item -ItemType Directory -Force两种 场景(新创建的目录或先前存在的目录)中都会返回 [System.IO.DirectoryInfo] 实例,代码会利用这一点。
# Create sample dir. with 2 sample files in it.
$tmpDir = New-Item -Force -Type Directory tmpDir
New-Item -Type File -Force -Path ('N30008xx.txt', 'N30005xx.txt' -replace '^', "$($tmpDir.FullName)/")

$dir = $tmpDir
$fileMask = 'N*.txt'

Get-ChildItem -File -LiteralPath $dir -Filter $fileMask | ForEach-Object {
  $newDir = Join-Path $dir $_.LastWriteTime.ToString("yyyy-MM-dd")
  $_ | Move-Item -Destination (New-Item -ItemType Directory -Force $newDir) 
}

警告重新概括此代码:

  • 您正在 source 目录中创建目标子目录。

  • 如果您要使用Get-ChildItem -Recurse 来处理源目录递归,您最终会处理匹配文件两次:首先在移动它们时,然后在他们移动到的位置找到它们时再次出现。
    (在这种特殊情况下,这只会导致效率低下,但是,因为处理已经移动的文件会尝试将它们移动到它们已经存在的目录中,这是一个安静的空操作。)

【讨论】:

    【解决方案2】:

    这是你的 PowerShell 的修改版本,应该可以工作。

    注意:您的目标目录不能位于源目录下,否则您将永远递归移动。

    $p = pwd
    $dst = "c:/tmp/testdir"
    
    Get-ChildItem -Path $p | Where-Object  {
        $_.PSIsContainer -eq $false
    } | ForEach-Object {
        $newdir = Join-Path -Path $dst -ChildPath ($_.LastWriteTime).ToString("yyyy-MM-dd")
        if (!(Test-Path -Path $newdir)) {
            Write-Host "Create directory $newdir"
            New-Item -Path $newdir -ItemType Directory
        }
        Write-Host "Copy file $_"
        Move-Item -Path $_ -Destination $newdir
    }
    

    【讨论】:

    • 它不会复制文件!
    • 虽然在被枚举的目录中重新创建新文件的警告通常值得关注,但在这种情况下没有问题,因为没有使用-Recurse。小心Move-Item -Path $_:只有当$p 也恰好是当前位置时它才会(很遗憾)起作用,因为$_ 有效地受仅文件名 的约束;要么使用$_.FullName,要么使用管道——见我的this answer(顺便说一句:最好使用-LiteralPath)。
    猜你喜欢
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 2016-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多