2013-07-05 21 views
11

Tôi cần sao chép tất cả các tệp *.doc (nhưng không phải thư mục có tên phù hợp với *.doc) từ thư mục mạng \\server\source (bao gồm tệp trong tất cả thư mục lồng nhau) vào thư mục cục bộ C:\destination mà không cần lưu trữ phân cấp thư mục lồng nhau. C:\destination và không có thư mục lồng nhau nào được tạo trong C:\destination). Trong trường hợp có nhiều tệp có cùng tên từ các thư mục con khác nhau của \\server\source, chỉ có một tệp đầu tiên sẽ được sao chép và không bao giờ ghi đè sau đó - tất cả các tệp xung đột được tìm thấy sau này sẽ bị bỏ qua (có thể có nhiều trường hợp như thế này và các tệp bị bỏ qua nên không được trasferred qua mạng, nếu không nó sẽ mất quá nhiều thời gian). Đây là nỗ lực của tôi để thực hiện nó trong PowerShell:Làm cách nào để sao chép các tệp nhất định (cấu trúc phân cấp thư mục), nhưng không ghi đè lên các tệp hiện có?

cp \\server\source\* -Recurse -Include *.doc -Container:$false -Destination C:\destination 

Có ít nhất hai vấn đề với lệnh này:

  • Nó sao chép thư mục có tên phù hợp *.doc quá.
  • Trong trường hợp các tên xung đột, bất kỳ tệp nào được tìm thấy sau này được chuyển qua mạng và ghi đè tệp trước đó.

Bạn có thể đề xuất cách khắc phục những sự cố này không?
Triển khai sử dụng copy, xcopy, robocopy, cscript hoặc *.bat, *.cmd cũng được hoan nghênh.
Hệ điều hành cục bộ là Windows 8 và hệ thống tệp là NTFS.

+0

Hành vi mong đợi nếu tập lệnh chạy hai lần là gì? Nó vẫn nên sao chép tất cả mọi thứ một lần? Hay nó không sao chép gì? –

+1

@splatteredbits Thư mục đích có thể được giả định ban đầu trống. Nếu điều kiện tiên quyết này thất bại thì hành vi kịch bản có thể không xác định. –

Trả lời

14

Tôi sẽ tạo danh sách các tệp trước và xác thực khi bạn duyệt qua danh sách.

Something như thế này:

$srcdir = "\\server\source\"; 
$destdir = "C:\destination\"; 
$files = (Get-ChildItem $SrcDir -recurse -filter *.doc | where-object {-not ($_.PSIsContainer)}); 
$files|foreach($_){ 
    if (!([system.io.file]::Exists($destdir+$_.name))){ 
       cp $_.Fullname ($destdir+$_.name) 
    }; 
} 

Vì vậy, sử dụng Get-ChildItem liệt kê các file trong thư mục nguồn phù hợp với bộ lọc, ống thông qua where-object dải danh bạ ra.

Sau đó xem qua từng tệp trong vòng lặp foreach và kiểm tra xem tên tệp (không phải Tên đầy đủ) tồn tại ở đích bằng cách sử dụng phương thức Exists của lớp system.io.file .NET.

Nếu không, sao chép, chỉ sử dụng tên tệp gốc (thả đường dẫn ban đầu).

Sử dụng -whatif tùy chọn trên bản sao khi thử nghiệm, vì vậy nó chỉ hiển thị những gì nó sẽ làm gì, trong kết quả trường hợp không phải là những gì bạn muốn :-)

+1

bạn đã bỏ lỡ khung –

+0

Thay vì '[system.io.file] :: Exists', bạn cũng có thể sử dụng 'Test-File' – jessehouwing

2
# Get all *.doc files under \\server\source 
Get-ChildItem -Path \\server\source *.doc -Recurse | 
    # Filter out directores 
    Where-Object { -not $_.PsIsContainer } | 
    # Add property for destination 
    Add-Member ScriptProperty -Name Destination -Value { Join-Path 'C:\destination' $this.Name } -PassThru | 
    # Filter out files that exist on the destination 
    Where-Object { -not (Test-Path -Path $_.Destination -PathType Leaf } | 
    # Copy. 
    Copy-Item 
0
$docFiles = Get-ChildItem -Path "\\server\source" -Recurse | Where-Object {$_.Attributes.ToString() -notlike "*Directory*" -and ($_.Name -like "*.doc" -or $_.Name -like "*.doc?")} | Sort-Object -Unique; 
$docFiles | ForEach-Object { Copy-Item -Path $_.fullname -Destination "C:\destination" }; 

Dòng đầu tiên đọc từng *. tệp doc và * .doc? (vì vậy nó cũng xem xét định dạng Office 2010. .docx), không bao gồm Thư mục và tệp trùng lặp.
Sao chép dòng thứ hai mỗi mục từ đích đến nguồn (thư mục C: \ đích phải tồn tại).
Nói chung, tôi khuyên bạn nên chia lệnh trên nhiều dòng vì dễ dàng hơn để tạo mã (trong trường hợp này là nhiệm vụ đầu tiên: lấy tệp, tác vụ thứ hai: sao chép tệp).

6

Các câu trả lời trước đó dường như quá phức tạp với tôi, trừ khi tôi hiểu nhầm điều gì đó. Điều này sẽ làm việc:

Get-ChildItem "\\server\source\" *.doc -Recurse | ?{-not ($_.PSIsContainer -or (Test-Path "C:\Destination\$_"))} | Copy-Item -Destination "C:\Destination" 

Không ai trong số các built-in lệnh - sao chép, xcopy hoặc robocopy - sẽ làm những gì bạn muốn trên riêng của họ, nhưng có một tiện ích gọi là xxcopy ý rằng, thuận tiện có sẵn tại http://www.xxcopy.com. Nó có một số tùy chọn tích hợp đặc biệt để làm phẳng các cây thư mục vào một thư mục duy nhất. Sau đây sẽ làm những gì bạn mô tả:

xxcopy "\\server\source\*.doc" "C:\Destination" /SGFO 

Tuy nhiên, xxcopy có các tùy chọn khác nhau để xử lý tên tập tin trùng lặp hơn chỉ cần sao chép một trong những đầu tiên gặp phải, chẳng hạn như thêm tên thư mục nguồn đến tên tập tin, hoặc thêm Xác định số tuần tự cho tất cả trừ cái đầu tiên, hoặc tất cả trừ cái mới nhất hoặc cũ nhất. Xem trang này để biết chi tiết: http://www.xxcopy.com/xxcopy16.htm

+0

Hmmm, tôi thực sự không hiểu điều này, trừ khi ai đó đã ngoại lệ các phrasing của dòng đầu tiên. Nó không được dự định như một sự xúc phạm, tôi chỉ cảm thấy rằng các câu trả lời đã được đăng đã đi qua các bước bổ sung cho một cái gì đó có thể được thực hiện đơn giản hơn. Không đơn giản và conciseness được coi là thích hợp hơn trong mã hóa miễn là bạn không hy sinh sự rõ ràng? Dù sao, OP đặc biệt nói rằng ông sẽ chào đón các giải pháp bằng cách sử dụng lệnh sao chép. Tôi đã cung cấp thông tin về tiện ích sao chép của bên thứ 3 được thiết kế để thực hiện chính xác những gì anh ta muốn thực hiện bằng một nút chuyển. Làm thế nào là "không hữu ích"? –

+0

Đã thử tùy chọn của bạn (tùy chọn đầu tiên) - tốt, nhưng làm phẳng cấu trúc phân cấp – Archeg

+2

Làm phẳng cấu trúc phân cấp là mục tiêu của câu hỏi: "không lưu giữ phân cấp thư mục lồng nhau (tức là tất cả các tệp sẽ chuyển trực tiếp vào C: \ đích và không thư mục lồng nhau sẽ được tạo trong C: \ destination) ". –

1

Tại sao sử dụng foreach khi bạn đã có đường ống? Tính toán cho chiến thắng!

Get-ChildItem -Recurse -Path:\\Server\Path -filter:'*.doc' | 
    Where { -not $_.PSIsContainer } | 
    Group Name | 
    Select @{Name='Path'; Expression={$_.Group[0].FullName}},@{Name='Destination'; Expression={'C:\Destination\{0}' -f $_.Name}} | 
    Copy-Item 
Các vấn đề liên quan