Ответ 1
В PowerShell версии 3.0 и новее это делается следующим образом:
Get-ChildItem -Path $sourceDir | Copy-Item -Destination $targetDir -Recurse -Container
Ссылка: Get-ChildItem
У меня есть структура каталогов, которая выглядит следующим образом:
C:\folderA\folderB\folderC\client1\f1\files
C:\folderA\folderB\folderC\client1\f2\files
C:\folderA\folderB\folderC\client2\f1\files
C:\folderA\folderB\folderC\client2\f2\files
C:\folderA\folderB\folderC\client3\f1\files
C:\folderA\folderB\folderC\client4\f2\files
Я хочу скопировать содержимое папок f1
в C:\tmp \, чтобы получить это
C:\tmp\client1\f1\files
C:\tmp\client2\f1\files
C:\tmp\client3\f1\files
Я попробовал это:
Copy-Item -recur -path: "*/f1/" -destination: C:\tmp\
Но он копирует содержимое без правильного копирования структуры.
В PowerShell версии 3.0 и новее это делается следующим образом:
Get-ChildItem -Path $sourceDir | Copy-Item -Destination $targetDir -Recurse -Container
Ссылка: Get-ChildItem
Используйте xcopy
или robocopy
, оба из которых были разработаны именно для этой цели. Предполагая, что ваши пути - это только пути к файловой системе, конечно.
PowerShell:
$sourceDir = 'c:\folderA\folderB\folderC\client1\f1'
$targetDir = ' c:\tmp\'
Get-ChildItem $sourceDir -filter "*" -recurse | '
foreach{
$targetFile = $targetDir + $_.FullName.SubString($sourceDir.Length);
New-Item -ItemType File -Path $targetFile -Force;
Copy-Item $_.FullName -destination $targetFile
}
Замечания:
-Force
чтобы фактически создать структуру папок. Я покопался и нашел множество решений этой проблемы, причем все они были неким изменением, а не просто командой copy-item. Конечно, некоторые из этих вопросов предшествуют PowerShell 3.0, поэтому ответы не являются неправильными, но с помощью PowerShell 3.0 я наконец смог сделать это, используя переключатель -Container
для Copy-Item:
Copy-Item $from $to -Recurse -Container
Это был тест, который я провел, без ошибок, и папка назначения представляла ту же структуру папок:
New-Item -ItemType dir -Name test_copy
New-Item -ItemType dir -Name test_copy\folder1
New-Item -ItemType file -Name test_copy\folder1\test.txt
# NOTE: with no \ at the end of the destination, the file
# is created in the root of the destination, and
# it does not create the folder1 container
#Copy-Item D:\tmp\test_copy\* D:\tmp\test_copy2 -Recurse -Container
# If the destination does not exist, this created the
# matching folder structure and file with no errors
Copy-Item D:\tmp\test_copy\* D:\tmp\test_copy2\ -Recurse -Container
Если вы хотите правильно скопировать структуру папок с помощью PowerShell, сделайте это так:
$sourceDir = 'C:\source_directory'
$targetDir = 'C:\target_directory'
Get-ChildItem $sourceDir -Recurse | % {
$dest = $targetDir + $_.FullName.SubString($sourceDir.Length)
If (!($dest.Contains('.')) -and !(Test-Path $dest))
{
mkdir $dest
}
Copy-Item $_.FullName -Destination $dest -Force
}
Это объясняет создание каталогов и просто копирование файлов. Конечно, вам нужно будет изменить вызов Contains() выше, если ваши папки содержат периоды или добавляют фильтр, если вы хотите найти "f1", как вы упомянули.
Container
переключатель (для Copy-Item) поддерживает структуру папок. Наслаждаться.
testing>> tree
Folder PATH listing
Volume serial number is 12D3-1A3F
C:.
├───client1
│ ├───f1
│ │ └───files
│ └───f2
│ └───files
├───client2
│ ├───f1
│ │ └───files
│ └───f2
│ └───files
├───client3
│ └───f1
│ └───files
└───client4
└───f2
└───files
testing>> ls client* | % {$subdir = (Join-Path $_.fullname f1); $dest = (Join-Path temp ($_
.name +"\f1")); if(test-path ($subdir)){ Copy-Item $subdir $dest -recurse -container -force}}
testing>> tree
Folder PATH listing
Volume serial number is 12D3-1A3F
C:.
├───client1
│ ├───f1
│ │ └───files
│ └───f2
│ └───files
├───client2
│ ├───f1
│ │ └───files
│ └───f2
│ └───files
├───client3
│ └───f1
│ └───files
├───client4
│ └───f2
│ └───files
└───temp
├───client1
│ └───f1
│ └───files
├───client2
│ └───f1
│ └───files
└───client3
└───f1
└───files
testing>>
Мне нужно было сделать то же самое, поэтому я нашел эту команду:
XCopy souce_path destination_path /E /C /I /F /R /Y
И в вашем случае:
XCopy c:\folderA\folderB\folderC c:\tmp /E /C /I /F /R /Y
И если вам нужно исключить некоторые элементы, создайте текстовый файл со списком исключений. Например:.
Создайте текстовый файл exclude.txt на диске C:\и добавьте в него:
.svn
.git
И ваша команда копирования будет выглядеть следующим образом:
XCopy c:\folderA\folderB\folderC c:\tmp /EXCLUDE:c:\exclude.txt /E /C /I /F /R /Y
Ниже работал для меня
@echo off
setlocal enableextensions disabledelayedexpansion
set "target=e:\backup"
for /f "usebackq delims=" %%a in ("TextFile.txt") do (
md "%target%%%~pa" 2>nul
copy /y "%%a" "%target%%%~pa"
)
Для каждой строки (файла) в списке создайте в целевой папке один и тот же путь, указанный в строке чтения (%% ~ pa - это путь элемента, на который ссылается %% a). Затем скопируйте прочитанный файл в целевую папку.
$sourceDir = 'C:\source_directory'
$targetDir = 'C:\target_directory'
Get-ChildItem $sourceDir -Recurse | % {
$dest = $targetDir + $_.FullName.SubString($sourceDir.Length)
If (!($dest.Contains('.')) -and !(Test-Path $dest))
{
mkdir $dest
}
Copy-Item $_.FullName -Destination $dest -Force
}
Этот код работает, особенно если вы используете Get-ChildItem в связи с методом filter/where-object.
Однако в этом коде есть одна небольшая ошибка: с помощью оператора "IF" и следующего кода "mkdir" будет создана папка в $ targetDir... после этого команда "copy-item" создаст ту же папку в папка, только что созданная командой "mkdir".
Вот пример того, как это работает для меня с функцией "Где-Объект". Вы можете просто опустить оператор IF.
$Sourcefolder= "C:\temp1"
$Targetfolder= "C:\temp2"
$query = Get-ChildItem $Sourcefolder -Recurse | Where-Object {$_.LastWriteTime -gt [datetime]::Now.AddDays(-1)}
$query | % {
$dest = $Targetfolder + $_.FullName.SubString($Sourcefolder.Length)
Copy-Item $_.FullName -Destination $dest -Force
}
Убедитесь, что пути не указаны с "\" в конце.