问题
Here is some code I made :)
@echo off
set source="R:\Contracts\"
set destination="R:\Contracts\Sites\"
ROBOCOPY %source% %destination% *.srt *.pdf *.mp4 *.jpg /COPYALL /R:0 /S
for /r %source in (*) do @copy "%destination" .
R:\Contracts\ is full of folders which have files in them.
I want to copy all to R:\Contracts\Sites\ and flatten the folder structure.
Everything copies well but also the folder structure.
Thank you
回答1:
No single command will flatten the hierarchy for you; you will have to use multiple commands. It can be done simply by using FOR /R to walk the hierarchy, coupled with your copy/move command of choice (move, copy, xcopy, robocopy). Because your destination is within the source hierarchy, you need an IF to prevent the destination from being a source.
Before proceeding you should stop and think about what happens if the same file name appears in multiple source folders. You can only have one version in your destination folder. Can you guarantee no duplicate names exist? If not, which file should be kept? How can you structure the command to keep the file you want? This complication is probably why no command was ever written to simply flatten a hierarchy.
Here is your ROBOCOPY command integrated with the FOR /R solution.
@echo off
set source="R:\Contracts"
set destination="R:\Contracts\Sites"
::Not sure if this is needed
::It guarantees you have a canonical path (standard form)
for %%F in (%destination%) do set destination="%%~fF"
for /r %source% %%F in (.) do if "%%~fF" neq %destination% ROBOCOPY "%%F" %destination% *.srt *.pdf *.mp4 *.jpg /COPYALL /R:0
回答2:
You could do that with a PowerShell one liner. In this example I filter out all the files with the .txt extension from all the subfolders. And then send them to the Move-Item Cmdlet.
Combine the Cmdlets get-Childitem (GCI for short), -recurse, maby -filter and then pipe the result to the Move-Item Cmdlet. Use -WhatIf first to check that the output is what you expected.
Move to current folder
get-Childitem -recurse -filter *.txt | Move-Item -WhatIf
Move to another folder
get-Childitem -recurse -filter *.txt | Move-Item -Destination c:\temp -WhatIf
回答3:
Similar to the previous Powershell option, I did the following to flatten a multi-subdirectory music folder:
#Get all files and not the directories
$files = Get-ChildItem -Path R:\Contracts -Recurse | Where {$_.PSIsContainer -eq $false}
#Copy items from sources to new destination
foreach ($file in $files){
Copy-Item -Path $file.FullName -Destination R:\Contracts\Sites\$($file.Name)
}
The Get-ChildItem with the -Recurse switch will get a listing of all sub-folders and files. The Where function is stripping out any directories by checking the boolean PSIsContainer property. Without stripping the directories the sub-folder structure would be created without files in them. This listing is stored in the $files variable.
The foreach function runs through the list of files in the $files variable and stores one item at a time in the $file variable. The Copy-Item function then uses the full path from $file.FullName and then copies the file to the destination with the same name from $file.Name.
回答4:
I recently had to tackle this problem, and many files that I wanted to move to from the hierarchy to a single folder had the same name as each other, and I wanted to still flatten the hierarchy without them to being over-written. What I did was write a script that moves the file, but renames it with the old hierarchy path in the name for example: source files:
C:\files\somefiles\file.txt
C:\files\otherfiles\file.txt
destination is C:\newdir\ files are created as
C:\newdir\somefiles-file.txt
C:\newdir\otherfiles-file.txt
here is the code, batch file 1 goes thru the files, batch file 2 renames and moves them (could also copy instead, if you want to preserve the source:
@echo off
for /r %%f in (*.*pr) do @renameandmovefilespart2.bat "%%f" "%%~ff" "%%~xf"
renameandmovefilespart2.bat
@echo off
Setlocal EnableDelayedExpansion
rem set the whole file path
set origWhole=%1
set origPathOnly=%2
set extension=%3
rem here you can set where the directory to hold the flattened hierarchy is
set destDir=c:\destinationDir\
rem set the directory to do a string replace
rem make this the starting directory, that you dont want in the newly renamed files
set startingDir=C:\starting\directory\
set nothing=
set slash=\
rem here you can set what the character to represent the directory indicator \ in the new files
set reaplcementDirectoryCharacter=--
set quote="
rem cut out the starting part of the directory
call set newname=%%origWhole:!startingDir!=!nothing!%%
rem replace slashes with new character
call set newname=%%newname:!slash!=!reaplcementDirectoryCharacter!%%
rem remove quotes
call set newname=%%newname:!quote!=!nothing!%%
rem @echo shortened: %newname%
rem @echo source path: %origPathOnly% newPath: %startingDir%
rem @echo extension: %extension%
rem rename the files
ren %origWhole% %newname%
rem prepare to move the file, clean up the source path
call set origPathOnly=%%origPathOnly:!quote!=!nothing!%%
move "%origPathOnly%%newname%" "%destDir%"
回答5:
There's an old PCMag utility called Sweep.exe that can operate the same command in the current and subdirectory. I wouldn't put the destination as a subdirectory of the source directory. Put the destination elsewhere.
http://www.rarewares.org/files/case/Sweep.zip
cd c:\contracts
sweep copy *.* c:\sites
This will copy everything from c:\contracts and underneath to c:\sites
I use a similar command to flatten the hierarchy of a directory.
Take care with duplicates and how you want to handle them. Do you want to overwrite or handle a different way.
来源:https://stackoverflow.com/questions/8690245/robocopy-copy-folders-content-to-a-single-folder