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
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 Copy-Item Cmdlet.
Combine the Cmdlets Get-Childitem (GCI for short), -recurse, and -filter and then pipe the result to the Copy-Item Cmdlet. Use -WhatIf first to check that the output is what you expected.
Copy to another folder (Use -WhatIf and verify the output to check your command before committing to copying the files):
Get-Childitem -recurse R:\Contracts -filter *.txt | Copy-Item -Destination R:\Contracts\Sites -WhatIf
To do multiple filetypes as you've asked, you can just run multiple commands, one for each filetype.
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
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.
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%"
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.
For those familiar with R copying files to a single folder could be easily scripted as follow. It is more efficient than ROBOCOPY for large sets and directory structures.
## R script - Flatten files in folder structure
# declare your paths
sourcepath<-C:\\Myfolder\\PicturesInStructure"
destpath<-"C:\\Myfolder\\PicturesTogether\\"
# read source filenames with path to vector variable
fileslist<-list.files(sourcepath,
pattern="*.jpg", # in this example copies JPG pictures
full.names=TRUE, # retrieves full path
recursive=TRUE, # runs through all subdirs
include.dirs=FALSE) # skips dir names (no to be copied)
# here you will get a head of your list
head(fileslist)
# ordinary loop by source filenames
for (i in 1:length(fileslist)) {
# Number of Slashes required to extract filename from the source path
NoS<-lengths(regmatches(fileslist[i], gregexpr("/", fileslist[i])))
# for lengthy processes it is good to know where you are with this
cat(i,fileslist[i]," \r")
# copy one file to a destination folder (full path composed with paste0())
file.copy(fileslist[i],paste0(destpath,unlist(strsplit(fileslist[i],"/"))[NoS+1]))
}
Related
So i'm currently trying to delete a bunch of subfolders that were created by a program, on a recurring basis because it will recreate the subfolders. I know how to schedule the batch file, right now my issue is how to efficiently create the batch file to begin with. To clarify, say i have a directory named D:\IGSG. There are 250 folders within D:\IGSG, and within each one of those is a folder named D:\IGSG\F252341\arg. I want to delete all of the \arg folders, from all ~250 F folders I have, without deleting the other files inside the F folders. Right now the only way to do it that I know of would be to have a batch that goes
cd D:\IGSG\F252341
del /Q arg
and to repeat those lines for every subfolder, but typing out those folder names for every folder in there would be tedious, especially considering new ones are created from time to time. So i'm looking for a way with a batch to delete the subfolder of a subfolder, without deleting other files, if that makes sense.
On the cmd line for /d /r X:\path in combination with a wildcard will enumerate all folders names arg the appended .? meets this requirement:
for /d /r D:\IGSG %A in (arg.?) do #echo rd /s /q "%A"
if the output looks right remove the echo.
In a batch file double the %-signs -> %%A
#Echo off
for /d /r D:\IGSG %%A in (arg.?) do echo rd /s /q "%%A"
One of the rare cases where batch/cmd line can compete with PowerShell.
This PowerShell script will recurse through the subdirectory structure and delete all files and subdirectories inside arg directories. Be sure to change the location of the IGSG directory to yours. When you are satisfied that the correct files will be deleted, remove the -WhatIf from the Remove-Item cmdlet.
Get-ChildItem -Directory -Recurse -Path 'C:\src\t\delsubs\IGSG\F*' -Filter 'arg' |
Remove-Item -Path {(Join-Path -Path $_.FullName -ChildPath '*')} -Recurse -Force -WhatIf
If you need to run it from a cmd.exe shell, put the code above into a file named 'dodel.ps1' and run using:
powershell -NoProfile -File .\dodel.ps1
I have a set of folders in a drive and need to extract the path and filename of all of the files who have similar names (i.e., index_lms.htm or index*.htm). I need these to go into a csv file, which I will manipulate and use in a mass upload template. Is this possible through cmd shell or a batch file? (It's been a while since I tried writing these.)
Today the size of the task got worse....... I now have 1000 English courses, and translated versions in German, Turkish and Russian. So I really needed a batch solution to extract these pathnames - thank you.
One other issue arose in the the filename cannot have spaces and I see that all of them have multiple spaces in their filenames. Is this easy to edit as the paths/filenames are read?
Quick answer to Gung - the files are loaded into an LMS system and the target file for elearning is normally index.html or index_lms.html or index_html5.html. However the LMS also serves up documents (my current issue) in my case they are all pdf with a standard naming convention
This batch will iterate the given folders and recursively search them for any file beginning with index and create a csv with a header and the columns File, Path and PathFile.
#Echo off
SetLocal EnableExtensions
( Echo "File","Path","PathFile"
For %%A in (
"X:\Test\"
"Y:\Home\Customer\"
"Z:\Users\UserName\"
) Do Call :Search "%%~A"
) > "%~dpn0.csv"
Goto :Eof
:Search
For /R %1 %%B in (index*.htm*) Do Echo "%%~nxB","%%~dpB","%%~fB"
The output file will have the same drive, path and name as the batch file but the extension .csv
This will create file out.csv. Substitute your own dir pattern match.
del 2>nul out.csv
for /f "delims=" %%f in ('dir/s/b c:\index*.htm') do <nul set /p =%%f,>>out.csv
Here is another way to do it in PowerShell.
PS C:\src\t> type .\f2csv.ps1
$dirs = 'C:\src\t', 'C:\labs'
foreach ($dir in $dirs) {
Get-ChildItem -File '*.txt' -Recurse |
Select-Object #{Expression={$_.FullName}; Label="filename"} |
Export-Csv -Path '.\f2csv.csv' -Delimiter ',' -NoTypeInformation
}
PS C:\src\t> .\f2csv.ps1
PS C:\src\t> type .\f2csv.csv
"filename"
"C:\src\t\iosloginfo\lognextnum.txt"
"C:\src\t\t\file1.txt"
"C:\src\t\t\file10.txt"
"C:\src\t\t\file2.txt"
Say I have a file named api-build009.jar and it exists in multiple directories.
D:\InstallDir\subdir1\
D:\InstallDir\subdir2\subdir21\
D:\InstallDir\subdir3\
D:\InstallDir\subdir4\subdir41\
D:\InstallDir\subdir5\
D:\InstallDir\subdir6\subdir61\subdir62\
D:\InstallDir\subdir7\
D:\InstallDir\subdir8\
I want to backup (and thus rename) the file into the same respective directory as the original file. I want to perform this operation for all directories above (8, in this example), copying the original file and then rename it to api-build009.jar.bak.
D:\InstallDir\subdir1\api-build009.jar.bak
D:\InstallDir\subdir2\subdir21\api-build009.jar.bak
D:\InstallDir\subdir3\api-build009.jar.bak
D:\InstallDir\subdir4\subdir41\api-build009.jar.bak
D:\InstallDir\subdir5\api-build009.jar.bak
D:\InstallDir\subdir6\subdir61\subdir62\api-build009.jar.bak
D:\InstallDir\subdir7\api-build009.jar.bak
D:\InstallDir\subdir8\api-build009.jar.bak
How can I perform this process using Windows CLI or PowerShell?
Thank you kindly in advance.
Once you write a file - sounds like the same file, and then you write backup the file in the same folder. Are these different versions or copies of the same file.
These scripts will copy the files to same name and location with .bak extension
Batch
#Echo off
PushD "D:\InstallDir"
For /f "delims=" %%A in (
'Dir /B/S api-build009.jar'
) Do Echo Copy "%%~fA" "%%~fA.bak"
Popd
PowerShell
Get-ChildItem -Path D:\InstallDir -File -Filter api-build009.jar|
ForEach { Copy-Item $_.FullName -Destination "$($_.Fullname).bak" -whatif}
If the output looks ok remove the echo in the batch / -whatif in the script
I have lots of files that need to go in specific folders. All the filenames have a certain pattern to them and all the folders that need to hold them.
How can I write a batch file with the following rule?
c:\s1_d1111_c1_p1.mpz needs to move to folder c:\SNC1111
c:\s1_d2222_c1_p1.mpz needs to move to folder c:\SNC2222
The filenames always have 4 digits that correspond to the folder. The number after s and c are always 1, and p can have any whole number after it.
This is for Windows Server 2008 R2 Standard
Thanks for your help!
Using Powershell
This sample move the files startin in jdk to a child folder jdk
$files = Get-ChildItem -File
for ($i=0; $i -lt $files.Count; $i++) {
$outfile = $files[$i].Name
if ($outfile.StartsWith("jdk")){
mkdir -Path "jdk" -Force
move $files[$i].FullName "jdk"
}
}
Modify to match your condition and paste the code in a Powershell window
#echo off
setlocal enableextensions
set "source=c:\"
set "targetBase=c:\SNC"
for /d %%f in ("%source%\"
) do for %%a in ("%%~ffs1_d????_c1_p*.mpz"
) do for /f "tokens=2 delims=_d" %%b in ("%%~na"
) do echo move /y "%%~fa" "%targetBase%%%b\%%~nxa"
endlocal
for %%f used to ensure source path will always have an ending backslash
for %%a used to enumerate the files to process from source
for %%b used to split the name in parts and do the move
move command is only echoed to console. If the output is correct, remove echo
I am attempting to create a batch file to copy several files listed in a text file to a new folder. I have found several threads relating to this, but I can still not get the batch to work properly. The problem I am encountering is that the files listed in the txt are all in different source locations and have different extensions. The list reads, for example:
C:\Users\Foo\Pictures\Photographs\September\P1030944.jpg
C:\Users\Foo\Videos\Art\Movies\Class\movie.avi
C:\Users\Foo\Music\Jazz\20051.mp3
...etc
All the copy commands I could find have to list either the source directory i.e.
set src_folder=c:\whatever\
set dst_folder=c:\foo
for /f %%i in (File-list.txt) DO xcopy /S/E/U "%src_folder%\%%i" "%dst_folder%"
or the extension i.e.
for /R c:\source %f in (*.xml) do copy "%f" x:\destination\
but I need it to gather that information from the list itself.
If it helps I know that there are only files of a possible 39 different specific extensions in the txt (*.jpg *.gif *.png ... *.xhtml *.xht)
Any help/ideas?
Start reading HELP FOR and then try the following at the command prompt
FOR /F %a in (input.txt) DO #ECHO COPY %a c:\newfolder\%~nxa
you can see that %a gets expanded to the actual line in the input file, and that %~nxa is a way to extract the name and the extension from the file.
After careful testing, move the command to your BAT file, replace %a to%%a, and remove the ECHO command
#echo off
SET destfolder=c:\newfolder
FOR /F "delims=" %%a IN (input.txt) DO COPY "%%a" "%destfolder%\%%~nxa"
notice the wraping of the names with quotes "; and the inclusion of the "delims=" option; both are needed in case filenames contain blanks.
Finally be careful with possible name duplicates in the destination folder. If that is possible, you need to find an strategy to cope with such collisions. But this can be the subject of another SO question, can't it?
One sample which worked for me...
Replace my directories C:\whatever and C:\temp\svn with yours...
assuming that your filelist is named antidump_list.txt and located under C:\temp\svn\
> set src_folder=C:\whatever
> set dst_folder=C:\temp\svn
> for /f %%i in (C:\temp\svn\antidump_list.txt) DO copy "%src_folder%\%%i" "%dst_folder%\%%i"
Regards,
Gottfried
I have found that the easiest way to do this is to use a powershell script.
$Files = Get-Content File-list.txt
$Dest = "C:\output"
foreach ($File in $Files) {
Copy-Item $File $Dest
}
If you need to run it from a batch file, paste the above script to file named CopyFiles.ps1 and add the following command to your batch file
powershell -executionpolicy bypass -file .\CopyFiles.ps1
Since, powershell is included by default on Windows7 and newer, this method is as easy as doing the same with batch commands only.