파일 이름을 기반으로 특정 디렉터리에 파일 복사

파일 이름을 기반으로 특정 디렉터리에 파일 복사

실제로 Batch 또는 PowerShell과 관련된 실제 접점은 없지만 현재 솔루션을 찾고 있는 직원 디렉터리를 설정했습니다. 여기서 문서는 스크립트를 통해 앞서 언급한 디렉터리에 자동으로 복사됩니다.

  • 복사할 문서는 현재 모두 하나의 폴더에 있으므로 디렉토리의 각 하위 폴더에 복사해야 합니다.
  • 문서의 파일 이름은 다음과 같이 구성됩니다. 여기서 XX/ XXXX는 과제에서 역할을 하는 변수입니다.
    • ABCD_123456_1234567_12345_XX.pdf
      ABCD_123456_1234567_12345_XXXX.pdf
  • 대상 디렉토리에는 이러한 항목도 포함되어 있으며 현재 약 50개의 다른 항목이 있습니다.

세 번째 밑줄과 파일 확장자 사이의 변수만 가리키는 것이 가능합니까? 세 자리 또는 다섯 자리 변수를 추가하면 달라질 수 있습니까?

  • 나는 이미 검색 기능을 사용했지만 주어진 예와 정확히 일치하는 것을 찾지 못했습니다.
    • 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
  • Basename(확장자가 없는 파일 이름)을 분할 _하고 Basename의 마지막 부분을 가져와서 $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 산출

이 명령은 존재하지 않는 경우 폴더를 생성한 다음 파일을 붙여넣고 파일이 폴더 내에 존재하는 경우 파일을 덮어씁니다.

업데이트:

확장자 없이 파일 이름을 찾는 명령(그리고 결과를 filenamewithouttext.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 = ...괄호로 묶은 정의로 바꾼 다음 dis 해당 정의 내의 변수에 대해 동일하게 작업했습니다. 또한 처음 사용과 할당을 결합했습니다. 결과는 다음과 같습니다.

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
        }
    }
}

읽기는 힘들지만 대규모 데이터 세트에는 그만한 가치가 있습니다.

관련 정보