根據檔案名稱將檔案複製到特定目錄

根據檔案名稱將檔案複製到特定目錄

我實際上與 Batch 或 PowerShell 沒有任何真正的接觸點,不過,我已經設定了一個員工目錄,我現在正在為其尋找解決方案,其中文件透過腳本自動複製到上述目錄中:

  • 目前要複製的文件都在一個資料夾中,應複製到該目錄的對應子資料夾中。
  • 文件的檔案名稱結構如下,其中XX/XXXX是在賦值中起作用的變數:
    • ABCD_123456_1234567_12345_XX.pdf
      ABCD_123456_1234567_12345_XXXX.pdf
  • 目標目錄也包含這些,目前大約有五十個不同的目錄

是否可以只指向第三個底線和檔案副檔名之間的變量,因為這些變數會有所不同,可能會添加三位數或五位數變數?

  • 我已經使用了搜尋功能,但沒有找到與給定範例完全對應的內容:
    • C:\ABCD_123456_1234567_12345_99\\11/17/19/1991\Directory\99_ABCD\
      C:\ABCD_123456_1234567_12345_9999\\11/17/19/1991\Directory\9999_ABCD\
    • 可能:
      C:\ABCD_123456_1234567_12345_999\\11/17/19/1991\ directory\999_ABCD\
      C:\ABCD_123456_1234567_12345_99999\\11/17/19/1991\Directory\99999_ABCD\

我嘗試使用 進行設置$FileName-split,但實際上並沒有成功,但我已經設法完成文件名以實際計數,如 30:27 所示:

  • C:\ABCD_123456_1234567_12345_99C:\ABCD_123456_1234567_12345_0099
  • 我正在努力解析目標資料夾,所有資料夾都存在且文件名中包含變量,到目前為止:
    $Directory = "C:\Folder\" 
    $FileNames = (Get-Item $Directory).GetFiles()
    
    foreach($FileName in $FileNames) {
      $Destination = "\\10.10.10.10\destinationfolder"
      { Move-Item -Path $FileName -Destination $Destination }
    }
    

有沒有辦法透過匹配移動文件,或者我還必須通過計數來解析所有目標資料夾,以便設定要檢查的部分?

這可能會形象化它

答案1

這將是一個 PowerShell 解決方案:

$Destination = "\\10.10.10.10\destinationfolder"
Get-ChildItem "C:\Folder" | ForEach-Object {
    $Head = ($_.BaseName -split '_')[0]
    $Tail = ($_.BaseName -split '_')[-1]
    $DestinationPath = Join-Path $Destination ("{0}_{1}" -f $Head, $Tail)
    New-Item -Path $DestinationPath -ItemType Directory -ErrorAction SilentlyContinue
    Copy-Item $_.FullName $DestinationPath -Force
}

更新:

根據您的評論,我想這更符合您的需求。但是,您必須確保每個結局都有一個匹配的資料夾。例如,如果有一個資料夾被調用abc_123,另一個資料夾被調用,def_123它將簡單地採用第一個資料夾,因為根據您的評論,我們只考慮結尾

$Destination = "\\10.10.10.10\destinationfolder"
Get-ChildItem "C:\Folder" | ForEach-Object {
    $Tail = ($_.BaseName -split '_')[-1]
    $Filter = "*_{0}" -f $Tail
    $DestDir = Get-ChildItem $Destination -Filter $Filter -Directory | Select-Object -ExpandProperty FullName -First 1
    if ($DestDir) {
        Copy-Item $_.FullName $DestDir -Force
    } else {
        "No Directory was found that matched the Filter {0} in Directory {1}" -f $Filter, $Destination | Write-Host
    }
}

它執行以下操作:

  • $Destination首先在變數中設定目標資料夾
  • 取得資料夾中的所有項目Get-ChildItem(如果您需要進行遞歸,請新增開關-Recurse,如果您只想新增某些檔案類型-Filter *.txt或任何其他副檔名)
  • 循環遍歷所有找到的文件ForEach-Object
  • 拆分基本名稱(即不含擴展名的檔案名稱)_並獲取基本名稱的最後一部分並將其保存在$Ending變數中
  • 透過將結束變數格式化為資料夾名稱來計算資料夾名稱-f
  • 用於Join-Path連接目標和計算的資料夾並將其保存在$Destinationpath
  • 如果該資料夾不存在,則建立該資料夾New-Item。如果它已經存在,則此行不會覆蓋現有資料夾
  • 將項目複製到目標資料夾Copy-Item

答案2

我不明白你的問題,但如果你想像這樣複製和貼上文件

ABCD_123456_1234567_12345_1.txt copy into 1_ABCD
ABCD_123456_1234567_12345_2.txt copy into 2_ABCD
ABCD_123456_1234567_12345_3.txt copy into 3_ABCD
ABCD_123456_1234567_12345_9999.txt copy into 9999_ABCD

那也許這個cmd指令可以幫助你

echo D|for /l %x in (1,1,20) do @xcopy ABCD_123456_1234567_12345_%x.txt ABC_%x\ /Y /Q

第二個命令具有相同的輸出:

for /l %x in (1,1,20) do @xcopy ABCD_123456_1234567_12345_%x.txt ABC_%x\ /Y /Q

你可以20改為9999 輸出

此命令將建立一個資料夾(如果不存在),然後貼上該文件,如果文件存在於資料夾內,它將覆蓋該文件

更新:

尋找不帶副檔名的檔案名稱的命令(並將結果附加到 filenamewithoutext.txt)

for /f %x in ('dir /b') do @echo %~nx>>filenamewithoutext.txt

讀取輸出檔案並將變數儲存到新檔案中 variables.txt

for /f "tokens=5 delims=_" %x in (filenamewithoutext.txt) do @echo %x>>variables.txt

讀取變數並將檔案複製到不同的資料夾中

for /f %x in (variables.txt) do @xcopy ABCD_123456_1234567_12345_%x.txt ABC_%x\ /Y /Q

你可以ABC_%x改為%x_ABC

答案3

當我讀到你的問題時,我認為這應該有效:

$Source      = 'C:\Folder\'
$Destination = '\\10.10.10.10\destinationfolder\'

Get-ChildItem -Path $Source -FIlter *.pdf -File | ? { ($BaseName = $_.BaseName) -match '_' } | ForEach{
    $Head       = $BaseName.Split('_')[0]
    $Tail       = $BaseName.Split('_')[-1]       ### (Index of -1) -> Last array element
    $SubFolder  = "$Tail`_$Head"                 ### *** Escaped <underscore> required ***
    If ( Test-Path ( $FullPath = Join-Path $Destination $SubFolder ) ) {
        Copy-Item -Literal $_.FullName $FullPath
    } Else {
        '"{0}" not copied because the directory "{1}" does not exist' -f $_.Name , $FullPath | Write-Output
    }
}

ForEach-對象String.Split() 方法連接路徑測試路徑複製專案


偵錯

我使用程式碼的這種變體來解決字串操作的問題,這發現了在擴展字串中使用下劃線的問題。將所有中間變數放入GridView快速掃描:

Get-ChildItem -Path $Source -FIlter *.pdf -File | ? BaseName -match '_' | ForEach{
    $Head       = $_.BaseName.Split('_')[0]
    $Tail       = $_.BaseName.Split('_')[-1]
    $SubFolder  = "$Tail`_$Head"
    $FullPath   = Join-Path $Destination $SubFolder

    [PSCustomObject]@{
        'Head'       = $Head
        'Tail'       = $Tail
        'SubFolder'  = $SubFolder
        'FullPath'   = $FullPath
        'SubExists'  = Test-Path $FullPath
    }
} | Out-gridview

最佳化

中間變數在開發/測試/調試期間非常有用,但可能會減慢執行多次的循環內的速度。因此,一旦賦值看起來很穩健,我就向後工作,首先將定義的表達式複製$SubFolder到剪貼板,然後用括號中括起來的定義替換 的$SubFolder出現$FullPath = ...,然後對該定義中的變數進行相同的操作。也將分配與首次使用結合。結果是:

Get-ChildItem -Path $Source -FIlter *.pdf -File | ForEach{
If ( ($BaseName = $_.BaseName) -match '_' ) {
        If ( Test-Path ( $FullPath=Join-Path $Destination "$($BaseName.Split('_')[-1])`_$($BaseName.Split('_')[0])" ) ) {
            Copy-Item -Literal $_.FullName $FullPath
        } Else {
            '"{0}" not copied because the directory "{1}" does not exist' -f $_.Name , $FullPath | Write-Output
        }
    }
}

讀起來很糟糕,但對於大數據集來說應該是值得的。

相關內容