stib
stib

Reputation: 3512

Powershell equivalent of cp -n, i.e. copy files without overwriting

I frequently have to copy large numbers of files between drives, and the process often gets started and stopped. In a posix shell I can use cp -n to not overwrite existing files, but there doesn't seem to be an equivalent "do not overwrite" switch for copy-item in powershell.

What that means is that if I have to stop and start the process I have to use

ls -Recurse|%{
    if (-Not(test-path($_fullname.replace("D:\", "E:\")))){
        cp $_.fullname $_.fullname.replace("D:\", "E:\");
    }
}

Works fine, but if I have a million files to copy, as sometimes happens, I'd imagine there's going to be some overhead having to execute test-path every time.

EDIT: BTW I tried robocopy.exe d:\thedir e:\thedir /XN /XO /S, but it took forever to scan for files that were already there. If I use the script above and I'm half way through a big session, there will be a few seconds pause before it starts copying new files; with robocopy it was spending minutes running through the already copied files, before it even started copying.

Upvotes: 2

Views: 2384

Answers (1)

Frode F.
Frode F.

Reputation: 54881

The alternative is to use [System.IO.File]::Copy(source,dest) which will throw an exception when the destionation exists, but then you have to deal with the overhead of exception-handling + creating directories, so it problably won't help much.

You can use the .NET Exists() methods directly to cut away some powershell-overhead (2/3) on the path-testing. I did not wrap the Exists()-calls in a function as that adds powershell-overhead.

#Avoid aliases in scripts. You want people to be able to read it later
Get-ChildItem -Recurse| ForEach-Object {
    if (-Not([System.IO.File]::Exists($_fullname.replace("D:\", "E:\")) -or [System.IO.Directory]::Exists($_fullname.replace("D:\", "E:\")))){
        Copy-Item -Path $_.fullname -Destination $_.fullname.replace("D:\", "E:\")
    }
}

Comparison:

Measure-Command { 1..100000 | % { [System.IO.File]::Exists("C:\users\frode") -or [System.IO.Directory]::Exists("C:\users\frode") } } | Select-Object -ExpandProperty totalseconds

6,7130002

Measure-Command { 1..100000 | % { Test-Path "C:\users\frode" } } | Select-Object -ExpandProperty totalseconds

22,4492812

Upvotes: 2

Related Questions