How to remove spaces (not replace with underscores) from several thousand files in bulk in Windows? Can I do this from the DOS command?
Currently:
file one.mp3
file two.mp3
All files need to become:
fileone.mp3
filetwo.mp3
Here is a script that can efficiently bulk rename files, stripping all spaces from the name.
:renameNoSpace [/R] [FolderPath]
#echo off
setlocal disableDelayedExpansion
if /i "%~1"=="/R" (
set "forOption=%~1 %2"
set "inPath="
) else (
set "forOption="
if "%~1" neq "" (set "inPath=%~1\") else set "inPath="
)
for %forOption% %%F in ("%inPath%* *") do (
if /i "%~f0" neq "%%~fF" (
set "folder=%%~dpF"
set "file=%%~nxF"
setlocal enableDelayedExpansion
echo ren "!folder!!file!" "!file: =!"
ren "!folder!!file!" "!file: =!"
endlocal
)
)
Assume the script is called renameNoSpace.bat
renameNoSpace : (no arguments) Renames files in the current directory
renameNoSpace /R : Renames files in the folder tree rooted at the current directory
renameNoSpace myFolder : Renames files in the "myFolder" directory found in the current directory.
renameNoSpace "c:\my folder\" : Renames files in the specified path. Quotes are used because path contains a space.
renameNoSpace /R c:\ : Renames all files on the C: drive.
In Windows:
Open a Command Prompt.
Go to the folder with the cd command (eg.: cd "paht of your folder").
Open a powershell by typing: powershell
Then input this: get-childitem *.mp3 | foreach {rename-item $_ $_.name.replace(" ","")}
Create a powershell file - *.ps1 extension
Write this code:
dir |
Where-Object { $_.name.Contains(" ") } |
Rename-Item -NewName { $_.name -replace " ","" }
save, then right click -> run with powershell
Open Powershell in windows and then type the following command after navigating to the folder where you want to rename the files
get-childitem *.mp3 | foreach { rename-item $_ $_.Name.Replace(" ", "") }
Let's Analyze it:
get-childitem *.mp3
This lists all files whose names end with .mp3. They are then piped to the next command with the | operator.
foreach { rename-item $_ $_.Name.Replace(" ", "") }
This replaces all instances of " " (white space in this case || this is the instance which is to be replaced) with nothing, denoted by "", effectively wiping the word from all the files in the directory.
You could also modify get-childitem *.mp3 to get-childitem – that would rename all the files in the directory, not just files whose names end with .mp3.
** Note **
If you do not like the above method there is a awesome software named Bulk Rename Utility. I used this software personally and you can get many tuts on youtube how to use it.
You can write a simple script that does this for one file/directory, e.g.:
#echo off
setlocal enableextensions enabledelayedexpansion
set "ARG=%~1"
ren "%ARG%" "%ARG: =%"
...and then if you'd like, run it over all the files and/or directories you care about. For instance, if you create the above script as myrenamingscript.cmd, you can run it over all non-dir files in the current dir by running:
for %f in (*) do #myrenamingscript.cmd "%~f"
#echo off
setlocal enableextensions enabledelayedexpansion
for %%f in (*.*) do (
set ARG=%%~nxf
rename "%%f" !ARG: =!
)
Since programmatically renaming files is risky (potentially destructive if you get it wrong), I would use a tool with a dry run mode built specifically for bulk renaming, e.g. renamer.
This command strips out the whitespace from all files in the current directory:
$ renamer --find "/\s/g" --dry-run *
Dry run
✔︎ file one.mp3 → fileone.mp3
✔︎ file two.mp3 → filetwo.mp3
Rename complete: 2 of 2 files renamed.
Plenty more renamer usage examples here.
The problem i have faced is that there is a possibility that there is already a file with the name you try to give to the new file (eg if there are 2 files in the folder named "file one.txt" and "file_one.txt" when you try to replace the spaces with underscores, one file will replace the other). So I made this script that checks if the new name already exists and if so places a number at the end of the file name (adds 1 to the number until there is no other file with that name). Instructions about what to change are at the top (commended out lines). Do not store the batch file in the same folder you have the files to be renamed if you use *.* option. I hope this helps.
#echo off
REM Instructions
REM This script repaces spaces from file names with underscores.
REM If you want to just remove the spaces uncomment lines 30 and 52 and comment out the lines 29 and 51.
REM set the following parameters.
REM pb is the folder containing the files we want to rename (fullpath)
REM tm is a temporary folder that will be created and deleted. Just put a folder that does not exist and is not used by anything else (fullpath).
REM all is the file type you want to raname. E.g. *.* for every file, *.txt for TXTs, *.pdf for PDFs etc
REM you don't have to change anything else
set pb=<folder containing the files to rename>
set tm=<a temp folder that does not exist>
set all=*.*
set pa=%pb%%all%
setlocal EnableDelayedExpansion
cd /d %pa%
set /a count=1
if not exist %tm% mkdir %tm%
for /f %%F in (%pa%) do (
set name=%%~nF
set name2=!name: =_!
REM set name2=!name: =!
set name3=!name2!%%~xF
if !name2! == %%~nF (
move /y %%~dpF\!name3! %tm%\ >nul
) else (
if not exist %%~dpF\!name3! (
if not exist %tm%\!name3! (
ren "%%F" "!name3!"
move /y %%~dpF\!name3! %tm%\ >nul
)
)
)
)
:rename
for /f %%F in (%pa%) do (
set name=%%~nF
set name2=!name: =_!
REM set name2=!name: =!
set name4=!name2!%count%
set name3=!name4!%%~xF
if !name2! == %%~nF (
move /y %%~dpF\!name3! %tm%\ >nul
) else (
if not exist %%~dpF\!name3! (
if not exist %tm%\!name3! (
ren "%%F" "!name3!"
move /y %%~dpF\!name3! %tm%\ >nul
)
)
)
)
set /a count = %count% + 1
set /a loop = 0
for %%F in (%pa%) do (set /a loop = 1)
if %loop% equ 1 goto rename
move /y %tm%\%all% %pb% >nul
rmdir /s /q %tm%
Just copy paste this to batch-file and save as c:\myfolder\r.bat
setlocal EnableDelayedExpansion
#echo off &cls
set p=%*
set p=!p: =!
set p=!p:^(=!
set p=!p:^)=!
set p=!p:^[=!
set p=!p:^]=!
set p=!p:^$=!
set p=!p:^&=!
set p=!p:^#=!
set p=!p:^;=!
set p=!p:^:=!
set p=!p:^,=!
set p=!p:^#=!
set p=!p:^_=!
set p=!p:^-=!
set e=%p:~-4%
ren "%*" %time:~6,2%%time:~9,2%%e%
exit
Add a registry ket at
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\*\shell\#myRENAME]
#=""
[HKEY_CLASSES_ROOT\*\shell\#myRENAME\command]
#="c:\myfolder\r.bat \"%1\""
done, now select files & just right-click select myRENAME
all the files will be renamed instantly.
Related
so i found this nice batch for window that would compress every file of the same extension in the same directory into bzip2 by dragging and dropping any of the files into it but i would like to take it further and make it that when i drag and drop a folder into it. it would compress all the files in it, including the sub-folders until it reaches the end. obviously i would guess it has something to do with looping with using %%d but i could not exactly figure it out.
#echo off
if [%1]==[] goto usage
for /f %%i in ("%1") do (
echo %%~di
echo %%~pi
echo %%~xi
set rootpath="%%~di%%~pi*%%~xi"
)
for %%f in (%rootpath%) do (
"C:\Program Files\7-Zip\7z.exe" a -tbzip2 "%%f.bz2" "%%f" -mx9
del "%%f" /s /f /q
)
echo Finished operations!
goto exit
:usage
echo You have to drag and drop a file on this batch script!
echo Sorry for the poor documentation, but if you'll want to use it, you have to edit the .bat file
echo The only thing you really need is to change the path to your 7-Zip installation
echo Then simply drag and drop a file in a folder you want to BZip2, and it'll do the rest automatically
:exit
pause
I share with you this helpful and well commented batch script posted by enteleform on superuser
I just modified this variable Set archivePath="%%~x.zip" to Set archivePath="%%~x.bz2"
How to make 7-zip do a whole bunch of folders
#Echo OFF
SetLocal EnableDelayedExpansion
Rem // 7-Zip Executable Path
Set sevenZip="C:\Program Files\7-Zip\7z.exe"
Rem // START: NewLine Variable Hack
Set newLine=^
Rem // END: NewLine Variable Hack !! DO NOT DELETE 2 EMPTY LINES ABOVE !!
Rem // Set ErrorLog Variables
Set errorCount=0
Set separator=--------------------------------------------------------
Set errorLog=!newLine!!newLine!!separator!!newLine!!newLine!
Set errorPrefix=ERROR #:
Set successMessage=All Files Were Successfully Archived
Rem // Loop Through Each Argument
SetLocal DisableDelayedExpansion
for %%x in (%*) do (
Rem // Use Current Argument To set File, Folder, & Archive Paths
SetLocal DisableDelayedExpansion
Set filePath="%%~x"
Set directoryFiles="%%~x\*"
Set archivePath="%%~x.bz2"
SetLocal EnableDelayedExpansion
Rem // Source Is A Folder
if exist !directoryFiles! (
Set sourcePath=!directoryFiles!
)
Rem // Source Is A File
if not exist !directoryFiles! (
Set sourcePath=!filePath!
)
Rem // Print Separator To Divide 7-Zip Output
echo !newLine!!newLine!!separator!!newLine!!newLine!
Rem // Add Files To Zip Archive
!sevenZip! A -TZIP !archivePath! !sourcePath!
Rem // Log Errors
if ErrorLevel 1 (
Set /A errorCount=errorCount+1
Set errorLog=!errorLog!!newLine!!errorPrefix!!sourcePath!
)
)
Rem // Print ErrorLog
if !errorCount!==0 (
Set errorLog=!errorLog!!newLine!!successMessage!
)
Echo !errorLog!!newLine!!newLine!!newLine!
Rem // Keep Window Open To View ErrorLog
pause
You could probably do that with a single line batch-file:
#For %%G In ("%~1")Do #If "%%~aG" GEq "d" (For /F Delims^= %%H In ('""%__AppDir__%where.exe" /R "%%~G" * 2>NUL|"%__AppDir__%findstr.exe" /EVIL ".bz2""')Do #"%ProgramFiles%\7-Zip\7z.exe" a -tbzip2 "%%~dpH%%~nH.bz2" "%%H" -mx9 -sdel -w >NUL 2>&1)&"%__AppDir__%timeout.exe" /T 3
If you'd like it over multiple lines for readability:
#For %%G In ("%~1") Do #If "%%~aG" GEq "d" (
For /F "Delims=" %%H In (
'""%__AppDir__%where.exe" /R "%%~G" * 2>NUL | "%__AppDir__%findstr.exe" /EVIL ".bz2""'
) Do #"%ProgramFiles%\7-Zip\7z.exe" a -tbzip2 "%%~dpH%%~nH.bz2" "%%H" -mx9 -sdel -w >NUL 2>&1
"%__AppDir__%timeout.exe" /T 3
)
These examples should only work if you drag and drop a directory onto it, or call it on the command line with a directory as the first argument.
#echo off
for /f %%i in ("%1") do (
echo %%~di
echo %%~pi
echo %%~xi
set rootpath="%%~di%%~pi*%%~xi"
)
for /R %%f in (*) do (
"C:\Program Files\7-Zip\7z.exe" a -tbzip2 "%%f.bz2" "%%f" -mx9 -x!"packall.bat"
del "%%f" /s /f /q
)
echo Finished operations!
goto exit
:usage
echo You have to drag and drop a file on this batch script!
echo Sorry for the poor documentation, but if you'll want to use it, you have to edit the .bat file
echo The only thing you really need is to change the path to your 7-Zip installation
echo Then simply drag and drop a file in a folder you want to BZip2, and it'll do the rest automatically
:exit
pause
Cheers to my friend Anya who found a solution, so the way it would work with the script above is that you make a batch file name it packall.bat
save it anywhere as it will delete itself at the end of the process.
when you want to compress bunch of files into bz2 you copy it and put it in inside a folder made with any name in your desktop.
make sure its name has no spaces nor its sub-folders as that may confuse batch and make it compress your desktop contents for some reason.
click on the batch, then it will compress all the files within the same folder its in and their sub-folders and automatically delete itself.
Video example:
http://billstuff.site.nfoservers.com/e79nwk69.mp4
IMPORTANT NOTE for some reason if there duplicate names of files with the same extension at sub-folders they will be deleted
Don't forget the folder and its sub-folder names should not have a space
Best of luck!
I have around 180K files which needs to be move to folders based on the file name.
Files are with different extensions. I need to take all file names which start with numbers and get the number untill the first '-' and make a folder. Move all the files with the number in the folder.
Need to exclude files which do not start with numbers.
Sample Data: File Names
123-ACBDHDJ.pdf
123-dhdjd.txt
5658-dgdjdk.txt
456477-gse.docx
For example; Based on the above data mentioned on Filenames Above, I want to do the following:
make folders 123, 5658 and 456477
Move the first two files in folder 123, 3rd file in folder 5658 and
last file in folder 456477.
Tried below script:
#echo off
setlocal enabledelayedexpansion
for %%A in (*.psd *.jpg *.html *.tif *.xls *.xlsx *.htm *.csv *.pdf *.docx *.TXT *.zip *.msg *.xlsb *.eml *.*) do (
echo file found %%A
for /f "delims=" %%B in ("%%A") do set fname=%%~nB
for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
for /f "tokens=1* delims=-" %%D in ("!fname!") do set folname=%%D
echo folder name !folname!
if not exist "!folname!" (
echo Folder !folname! does not exist, creating
md "!folname!"
) else (
echo Folder !folname! exists
)
echo Moving file %%A to folder !folname!
move "%%A" "!folname!"
)
echo Finished
pause
Issues currently facing:
Folders created with alpha numeric characters as well, I wanted to
ignore those files and pick only the ones starting with numbers.
Script running too long, very slow performance . Data volume is
very high, 180K records.
Please help with a batch script for this or any faster way to do this as the data volume is very huge. Thanks in advance.
Let's consider why it takes long. You have 128k files, you run 4 loops, meaning the for loops themselfs process each file 5 times, that is 640 000 processes on its own, you then run echos for each, that is even more processes, then we you check if a folder exists and if not create it, the folder exists is another process.. I guess you are getting where I am going with this. You are effectively running over a million procces to complete this task.
Maybe we get rid of all the unwanted for loops, use * instead of naming each file, then get rid of delayed expansion as we can simply get away without having to set variables:
#echo off
for %%i in (*) do (
echo file found %%i
for /f "tokens=1* delims=-" %%a in ("%%i") do (
if "%%a-%%b"=="%%i" (
md %%a>nul
move "%%~fi" %%a
)
)
)
echo Finished
pause
As for the name and extension part, you never use them after setting, If you still want to somewhere use the name and extension of the files, then you just use them without having to set vars:
#echo off
for %%i in (*) do (
echo file found %%i
for /f "tokens=1* delims=-" %%a in ("%%i") do (
if "%%a-%%b"=="%%i" (
md %%a>nul
move "%%~fi" %%a
echo This is the file extension: %%~xi
echo This is the filename: %%~na
echo This is the filename, drive and path: %%~dpi
echo This is the filename with full path: %%~fi
)
)
)
echo Finished
pause
You are using a lot of unnecessary code, which makes your batch file too slow. I would suggest something like:
#echo off
for %%A IN (*.*) do (
if not "%%~fA" == "%~f0" (
echo File found: %%A
for /f "tokens=1* delims=-" %%B IN ("%%~nxA") do (
md %%B>nul
(move "%%~fA" "%%~dpA%%B")>nul
)
)
)
echo Finished
pause
exit /b %errorlevel%
It seems also that the other loops you are making are useless. You can directly use %%~nA, %%~xA, e.t.c. See output of for /? in cmd.
You may already have an answer with the .bat file scripts. Here is a way to do it in PowerShell. When the script is tested and will move the files correctly, remove the -WhatIf from the Move-Item cmdlet.
$sourcedir = './s'
$destdir = './d'
Get-ChildItem -File -Path "$sourcedir/*" |
ForEach-Object {
if ($_.Name -match '^(\d+)-.*') {
$ddir = Join-Path $destdir $Matches[1]
if (-not (Test-Path -Path $ddir)) { New-Item -Name $ddir -ItemType Directory }
Move-Item -Path $_.FullName -Destination $ddir -WhatIf
}
}
This can be run from a cmd shell by saving the script into a file (thefile.ps1) and using the following command or putting the command into a .bat file script.
powershell -NoLogo -NoProfile -File thefile.ps1
I would do it the following way -- see all the explanatory remarks (rem) in the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=%~dp0." & rem /* (directory containing all the files; `%~dp0` points to the
rem parent directory of this batch script; to use the current
rem working directory, simply specify a single `.`) */
set "_MASK=?*-*.*" & rem /* (search pattern to find files, matching only files with at
rem least one hyphen in their names) */
set "_FILTER=^[0123456789][0123456789]*-" & rem /* (`findstr` filter expression;
rem this matches only files whose name begin with one or more
rem decimal digits followed by a hyphen) */
rem // Change to given root directory:
pushd "%_ROOT%" && (
rem // Loop through all matching files:
for /F "tokens=1* delims=-" %%E in ('
rem/ Return files and filter out those with non-numeric prefix: ^& ^
dir /B /A:-D "%_MASK%" ^| findstr /R /I /C:"%_FILTER%"
') do (
rem // Try to create target directory:
ECHO md "%%E" 2> nul
rem // Move file into target directory:
ECHO move /Y "%%E-%%F" "%%E\"
)
rem // Return from root directory:
popd
)
endlocal
exit /B
After having tested the script for correct output, remove both upper-case ECHO commands!
I have to manipulate dozens if not hundreds of images fairly often. When I get the images, it's often 1018u182012480d1j80.jpg type filenames, so I can select all of the images, and then hit 'F2' to rename them all to image (1).jpg | image (2).jpg | ... etc. Can someone write me a batch script to remove the parentheses and the spaces in the file names?
If possible, it'd be great if I didn't even have to open it up and edit the batch file to update the current dir, I.E, if it can just use %CD% or something to get the current folder, that would be awesome.
I don't understand batch files at all but here's one I found that will remove the parentheses, but I have to add the sourcedir.
#ECHO OFF
SETLOCAL
SET "sourcedir=C:\.." #Can we make this just find the location?
FOR /f "delims=" %%a IN (
'dir /b /s /a-d "%sourcedir%\*" '
) DO (
SET "name=%%~na"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "newname=!name:)=!"
SET "newname=!newname:(=!"
IF "!name!" neq "!newname!" (
IF EXIST "%%~dpa!newname!%%~xa" (ECHO cannot RENAME %%a
) ELSE (REN "%%a" "!newname!%%~xa")
)
endlocal
)
The script should work if file names/paths does not contain any ! exclamation mark.
Supply a folder path as an argument (see sample calls below). This can be done even by file explorer's drag&drop feature (drag a folder, drop on batch). Read call /? or Command Line arguments (Parameters) for %~1 explanation.
Narrow to only .jpg files using "%sourcedir%\*.jpg" in FOR /f line.
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
SET "sourcedir=%~1" supplied string
if NOT defined sourcedir SET "sourcedir=%CD%" current directory if nothing supplied
rem basic validity check
if NOT exist "%sourcedir%\*" (
echo wrong directory "%sourcedir%"
goto :next
)
FOR /f "delims=" %%a IN ('dir /b /s /a-d "%sourcedir%\*" ') DO (
SET "name=%%~na"
SETLOCAL ENABLEDELAYEDEXPANSION
rem remove ) right parenthesis
SET "newname=!name:)=!"
rem remove ( left parenthesis
SET "newname=!newname:(=!"
rem remove ↓ space(s)
SET "newname=!newname: =!"
IF "!name!" neq "!newname!" (
IF EXIST "%%~dpa!newname!%%~xa" (
ECHO cannot RENAME %%a
) ELSE (
rem operational RENAME command is merely ECHO-ed for debugging purposes
ECHO RENAME "%%a" "!newname!%%~xa"
)
)
ENDLOCAL
)
:next
rem pause to see output
pause
Sample call without argument - applies to the current directory:
d:\bat\SU> D:\bat\SO\43097467.bat
RENAME "d:\bat\SU\New Text Document.txt" "NewTextDocument.txt"
RENAME "d:\bat\SU\Files\ruzna pisma.png" "ruznapisma.png"
RENAME "d:\bat\SU\Files\volume control options.png" "volumecontroloptions.png"
RENAME "d:\bat\SU\Files\volume mixer.png" "volumemixer.png"
RENAME "d:\bat\SU\Files\1126981\ERKS 100004_thumb.jpg" "ERKS100004_thumb.jpg"
Press any key to continue . . .
Sample call with argument - applies to the supplied directory:
d:\bat\SU> D:\bat\SO\43097467.bat D:\test\43097467
RENAME "D:\test\43097467\image do - Copy (2).bmp" "imagedo-Copy2.bmp"
cannot RENAME D:\test\43097467\image do - Copy (3).bmp
RENAME "D:\test\43097467\image do - Copy (4).bmp" "imagedo-Copy4.bmp"
Press any key to continue . . .
Sample call, argument with spaces must be enclosed in a pair of double quotes:
d:\bat\SU> D:\bat\SO\43097467.bat "D:\bat\odds and ends\a b"
RENAME "D:\bat\odds and ends\a b\c d\my list_Utf8.txt" "mylist_Utf8.txt"
RENAME "D:\bat\odds and ends\a b\c d\e f\h i batch.bat" "hibatch.bat"
RENAME "D:\bat\odds and ends\a b\c d\e f\System locale.png" "Systemlocale.png"
Press any key to continue . . .
d:\bat\SU>
i have a lot of folders with a random number of files within.
And the most of them just have 1 file inside it, these files needs to move to the parent folder. but i don't know how i should do it with a batch file.
I use Windows 7 Ultimate
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /d /r "%sourcedir%" %%a IN (*) DO (
FOR /f %%c IN ('dir /b/a-d "%%a\*.*" 2^>nul ^|find /c /v ""') DO IF %%c==1 ECHO(MOVE "%%a\*.*" "%%a\..\"
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
The for /d /r finds all of the subdirectory names starting at sourcedir and assigns thenm to %%a in turn.
Each directory is then examined for filenames only; the 2>nul suppresses error messages for empty directories, and the output of the dir command is fed to find which counts (/c) the number of lines which don't match "" (ie. counts the lines of directory = # files returned). This is applied to %%c
If %%c is 1, then move all (one) files from the directory to its parent.
The required MOVE commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)
This solution don't use any external .exe command, so it should run faster. Also, it is clear enough to be understood with no problems, I think...
#echo off
setlocal EnableDelayedExpansion
for /D %%d in (*) do (
set "firstFile="
set "moreThanOneFile="
for %%f in ("%%d\*.*") do (
if not defined firstFile (
set "firstFile=%%f"
) else (
set "moreThanOneFile=true"
)
)
if not defined moreThanOneFile move "!firstFile!" "%%d"
)
You have a number of folders that all may or may not contain files within them, and you want to move all files to some other directory?
PowerShell is the new and improved super charged version of using a batch file, and this is how you'll do it.
Run PowerShell
paste in the following
dir -Recurse C:\FolderContainingManySubfolder | ? PSIsContainer | dir -Recurse | move-item -Destination T:\somePath -WhatIf
Replace C:\FolderContainingManySubfolder with the folder that has all of those other folders with one or two items each, and replace T:\somePath with the place you want the single files to go.
Run it, and you'll see a lot of 'What If' output, which shows you what would happen if you were to run the command. If you're happy with what you see, then remove the -WhatIf parameter from the end.
I have two folders that contain all the same files and subfolders, but the conents inside each file may have changed. I want to write a batch file that will search through each file and look for any differences. What's the best tool for what I want to do?
No need for a batch file. A single FC command can do what you want:
fc folder1\* folder2\*
You can be more specific for the file mask in the first folder if you want. For example folder1\*.txt.
The command will report on files that exist in folder1 but are missing in folder2. Extra files in folder2 are simply ignored.
There are a number of options to the FC command. Enter HELP FC or FC /? from the command prompt to get more information.
EDIT
Extending the solution to support subfolders is a bit tricky. It is easy to iterate the folder hierarchy for a given root using FOR /R. The problem is getting the relative paths so that the hierarchy can be applied to another root.
The simplest solution is to use FORFILES instead, since it directly supports relative paths. but FORFILES is... S L O W :/
At this point, a batch file makes sense:
#echo off
setlocal
set "folder1=c:\path\To\Folder1\Root"
set "folder2=d:\path\To\Folder2\Root"
set "fileMask=*"
for /f "delims=" %%F in (
'echo "."^&forfiles /s /p "%folder1%" /m "%fileMask%" /c "cmd /c if #isdir==TRUE echo #relpath"'
) do fc "%folder1%\%%~F\%fileMask%" "%folder2%\%%~F\*"
Here is another way to accomplish the task. Set the variables Folder1 and Folder2 to the full path of the folders you want to compare and run the batch file.
Output:
Dup – the file exists in both folders and are identical.
Dif - the file exists in both folders but the content of the files are different.
New – The file exists in one folder but not the other.
#Echo Off
SetLocal EnableDelayedExpansion
Set "Folder1=%UserProfile%\Desktop\Test Folder1"
Set "Folder2=%UserProfile%\Desktop\Test Folder2"
For /R "%Folder1%" %%x In (*.*) Do (
Set "FullPath=%%x"
Set "RelPath=!FullPath:%Folder1%=!"
If Exist "%Folder2%!RelPath!" (
>Nul 2>&1 FC /b "%Folder1%!RelPath!" "%Folder2%!RelPath!" && (
Echo Dup - %%x
)||(
Echo Dif - %%x
)
) Else (
Echo New - %%x
)
)
For /R "%Folder2%" %%x In (*.*) Do (
Set "FullPath=%%x"
Set "RelPath=!FullPath:%Folder2%=!"
If Not Exist "%Folder1%!RelPath!" (
Echo New - %%x
)
)
I'm having better luck with the following batch file. The path names have to completely match though; so only the Drive Letter differs.
Mapping a shared network folder may make this easier. I can't say for sure for your case.
'---
setlocal
set "folder1=D:\User\Public"
set "Drv2=E:"
set "fileMask=*"
setlocal
set "folder1=<DrvLttr>:\<Folder>\<SubFolder>"
set "Drv2=<DrvLttr2>:"
set "LogFile=<SystemDrv>\User\<UserName>\<LogFileName>"
ECHO "the '>' may OVER WRITE or make a ~NEW~ File for the results" > "%LogFile%"
ECHO " '>>' adds to the end of the file >> "%LogFile%"
FOR /R %folder1% %%A in ( *.* ) DO FC "%%A" "%Drv2%%%~pnxA" 1>> "%LogFile%" 2>&1
If you wish to note what is going to be the command for testing, you can try inserting ECHO after DO. You can drop the 1>>... stuff to see the result on screen, instead of having to open the output file.
I modified a batch file I wrote for a CD process that should meet your need. It
takes 2 directory trees and compares each file in each tree
creates a list of the file differences (named File_differences.txt in the output folder)
and creates a folder with a diff file for each non-matching object
If both directory structures are under the same parent, then all you need to do is update the first 8 variables in the script. If the directory trees have different parents, then read through the scripts comments. Particularly lines 14, 38 and 46.
:: This script compares the contents of 2 trees
:: set a workspace location for the script outside of the trees being reviewed
set home=D:\path\to\batch_file_home
set Input=D:\path\to\batch_file_home\Input_Files
set Resource=D:\path\to\batch_file_home\Resource_Files
set Output=D:\path\to\where your want to view your\Output_Files
set environment=D:\path\to\parent directory containing the different tree structures (if they do not share a parent, then make this the drive)
:: the next 3 lines are only needed if you want to predefine multiple directories for comparison
set Prod=production
set QA=test
set Dev=branches\dev
:: If you remove the 3 lines above, then you need to replace the 2 below variables with values
:: If the trees are not under the same parent, then include the full path for Tree A and B below
set Tree_A=%Prod%
set Tree_B=%QA%
:: if you already have an object list, place it in the Input folder and remove lines 24 through 35 of this script
set Object_List=Object_List_minus_Direcotries.txt
set Output_File=File_differences.txt
if exist %Output%\%Output_File% del %Output%\%Output_File%
if exist %Output%\Differences\*.txt del %Output%\Differences\*.txt
if exist %Resource%\* del /q %Resource%\*
:: since you state the objects in both trees are always the same, I have not included a comparison to verify the 2 trees match
:: this section identifies the contents of Tree A
cd %environment%\%Tree_A%
dir /b /s > %Resource%\Complete_Tree_A_Object_List.txt
:: Next, remove the objects that are directories
setlocal enabledelayedexpansion
for /f "tokens=*" %%p in (%Resource%\Complete_Tree_A_Object_List.txt) do (
dir /a:d /b %%p 2>nul >nul && (set object_type=folder) || (set object_type=file)
echo !object_type!
if !object_type!==file echo %%p >> %Resource%\%Object_List%
)
:: in the object list, remove the parent tree from the path
:: if the Trees are not under the same parent, then comment out the below 6 lines
powershell -command "(Get-Content %Resource%\%Object_List%) -replace '\\','/' | set-content %Resource%\%Object_List%"
powershell -command "(get-content %Resource%\%Object_List%) | Foreach {$_.TrimEnd()} | Set-Content %Resource%\%Object_List%"
set remove_parent_prefix=%environment%\%Tree_A%
set remove_parent_prefix=%remove_parent_prefix:\=/%
powershell -command "(Get-Content %Resource%\%Object_List%) -replace '%remove_parent_prefix%/','' | set-content %Resource%\%Object_List%"
powershell -command "(Get-Content %Resource%\%Object_List%) -replace '/','\' | set-content %Resource%\%Object_List%"
:: the below loop assumes both Trees are under the same parent. If this is not the case, replace the cd %environment% line with cd %home%
:: when the Trees are not under the same parent, set home to the root location, example cd D:\
setlocal enabledelayedexpansion
for /f "tokens=*" %%x in (%Resource%\%Object_List%) do (
set Diff_File=%%x
set Diff_File=!Diff_File:\=-!
cd %environment%
fc %Tree_A%\%%x %Tree_B%\%%x > "%Output%\Differences\!Diff_File!-%Output_File%"
for %%a in ("%Output%\Differences\!Diff_File!-%Output_File%") do for /f %%b in ('find /c /v "" ^< "%%a" ') do if %%b LSS 3 del "%%a"
for %%R in ("%Output%\Differences\!Diff_File!-%Output_File%") do if not %%~zR lss 1 (
echo %%x >> %Output%\%Output_File%
)
for %%R in ("%Output%\Differences\!Diff_File!-%Output_File%") do if %%~zR lss 1 (
del "%Output%\Differences\!Diff_File!-%Output_File%"
)
)
endlocal
:: Clean up Resources. If you want to review the temp files used to create the report, comment out the below line
if exist %Resource%\* del /q %Resource%\*