I want to create a batch file to compare two folders with the same set of files and copy any files that are different in size from one folder to the other. I tried to adapt the answer from another question as follows as a starting point, but even this doesn't work.
#echo off
Set folder1="C:\folder1"
Set folder2="C:\folder2"
Cd /D "%folder1%"
For %%a in (*.*) do (
For %%b in ("%folder2%\%%a") do (
If "%%~Za" neq "%%~Zb" echo Different file size in %%a
)
)
Update1:
I figured out what was wrong in the example above; it was the quotes around the directories in the set folder commands. The following works as it should:
#echo off
Set folder1=C:\folder1
Set folder2=C:\folder2
Cd /D "%folder1%"
For %%a in (*.*) do (
For %%b in ("%folder2%\%%a") do (
If %%~za neq %%~zb echo Different file size %%a
)
)
Update2:
So this finally does what I want (compares two folders with the same set of files and copies any files that are different in size from one folder to the other):
#echo off
Set folder1=C:\folder1
Set folder2=C:\folder2
Cd /D "%folder1%"
For %%a in (*.*) do (
For %%b in ("%folder2%\%%a") do (
If %%~za neq %%~zb xcopy "%folder1%\%%a" "%folder2%" /y
)
)
The classic way to do this is
xcopy /L /y /d "directory1\*" "directory2"
The /L LISTS the files that would be copied. /d actually says "if the source file in the first parameter is later than the file in the second" which may not be what you want. The /y prevents a prompt for ovewrite (with the /L switch, just a listing is created, but still...)
Files existing in the source but not in the destination will be copied to the destination (or listed if the /L switch is used)
Remove the /L switch to actually perform the copy.
Add /s to repeat for all subdirectories of the source.
Related
I am in the middle of batch extracting screenshots for contents we are planning to use on a tube site I am working on.
The jpeg files per content is labled as followed:
6c82c0239f6eb839-1
6c82c0239f6eb839-2
all the way to 120
The file name is different per content
a82384e2c46ba4af-1
a82384e2c46ba4af-2
etc.
They will all be extracted to a singe folder.
So I basically need a batch file that will create folders based on the content name without the dash and number and move all 120 jpegs in the folder with the content name.
For example:
Create folder named 6c82c0239f6eb839 and
move 6c82c0239f6eb839-1 to 6c82c0239f6eb839-120 in to the created folder.
I saw another thread with the following batch file. its pretty much what I want but the folder name is only 3 characters long and the files are copied to the newly created folders instead of moving them.
#echo off
SetLocal EnableDelayedExpansion
for /F "delims=" %%a in ('dir /b *.jpeg') do (
set Name=%%a
set Folder=!Name:~0,3!
xcopy /y "%%a" !Folder!\
)
Could someone change this so that it will display full file name without the dash and number for the folders and move files in its respective folders instead of copy?
Thank you
#echo off
setlocal
#rem Get each jpeg file.
for /F "delims=" %%A in ('2^>nul dir /b *.jpeg') do (
rem Get filename as token before the dash.
for /f "delims=-" %%B in ("%%~A") do (
rem Make dir if needed.
if not exist "%%~B" md "%%~B"
rem Check if isdir.
2>nul pushd "%%~B" && popd
if errorlevel 1 (
>&2 echo Failed isdir "%%~B".
) else (
rem Do the move operation.
>nul move /y "%%~A" "%%~B"
if errorlevel 1 (
>&2 echo Failed move "%%~A" to "%%~B"
)
)
)
)
exit /b %errorlevel%
The code is well remarked so if you want to understand
the evaluated code by changing #echo off to #echo on.
The use of %errorlevel% after the exit /b is not
required though will let you know what the errorlevel is
when #echo on is used.
The pushd tests for a directory
(even if it is a symlink).
errorlevel is checked to decide if to echo a
error message or do the move.
As the for loop variables are used direct, use of
enabledelayedexpansion is not needed.
Many commands support the argument of /? to get help
about the command. i.e. move /?.
If you only try to copy the correct jpeg to the correct folder, you can do this:
#echo off
SetLocal EnableDelayedExpansion
CD <CORRECT ROOT PATH>
for /F "delims=" %%a in ('dir /b *.jpeg') do (
set Name=%%a
REM I presume all the files have 16 characters before the dash
set Folder=!Name:~0,16!
IF NOT EXIST !Folder! MKDIR !FOLDER!
xcopy /y "%%a" !Folder!\
)
I was not able to test.
First of all, I would like to apologize for my manners regarding my initial post.
The answer by micheal_heath has resolved my issue.
Furthermore, I happened to find this post by user Salmon Trout from a different site which also worked.
Batch file to make folders with part of file name and then copy files
#echo off
setlocal enabledelayedexpansion
for %%A in (*.psd *.jpg) 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
I just changed the the following line remove the hypen and numbers to create folders for the file name properly.
for /f "tokens=1* delims=-***" %%D in ("!fname!") do set folname=%%D
I still lack the knowledge on why and how both methods work, but this has been an interesting start for me. I hope other beginners trying to solve a similar issue can find something useful from this post.
I've got a script that I'm using for all kinds of things, including renaming and repacking comics. Variants of this script are used by others as well.
I've been seeing a limitation in repacking comics, however; I've found that some comics don't have the leading zeroes at their pages, which makes the pages appear out of order. So, I've added a part that should add leading zeroes.
The file does the following:
loop over all subfolders of the current folder
rename comic archives to their proper extension (so I can see where it is)
loop over all archives, and extract them to a temporary folder
loop over all files in the temporary folder, and add leading zeroes
repack it as a 7zip
rename the file to a comic book extension
Somehow, it's not renaming the files properly, and the name of the archive appears as a subfolder in the archive. For example:
let's repack 'testfolder', which contains images from 1 to 100. It renames, extracts, packs, and renames again, without problem. However, the new archive contains the folder named 'testfolder' in the archive next to the images, which don't have the leading zeroes. I'm not sure what's going on, and I've been fighting with it for a while now, so I thought to put it online (it's a good script to share, anyway). Does anyone have an idea on what's going wrong here?
#ECHO ON
rem mode con: cols=80 lines=60
for /f "delims=" %%F in ('dir /ad/s/b') do (
cd %%F
IF EXIST *.cbr (
RENAME *.cbr *.rar
)
IF EXIST *.cbz (
RENAME *.cbz *.zip
)
IF EXIST *.cb7 (
RENAME *.cb7 *.7z
)
FOR %%I IN (*.RAR, *.ZIP *.7Z) DO (
ECHO Extracting %%I...
"C:\Program Files\7-Zip\7z.exe" e "%%I" -oC:\TMPPACKDIR\* -y | FIND /V "ing "
echo %%~nI
cd C:\TMPPACKDIR\%%~nI\
FOR /f "delims=" %%P IN ('dir *.JPG, *.PNG, *.BMP') DO (
SET %%N = %%P
SET %%N = 00%%N
SET %%N = %%N:~-2%
echo %%P
echo %%N
pause
rename 'C:\TMPPACKDIR\%%~nI\%%P' %%N
)
pause
echo %%F
cd %%F
ECHO Repacking
"C:\Program Files\7-Zip\7z.exe" a -t7z "%%~nI.7z" "C:\TMPPACKDIR\%%~nI*" -mx=9 | FIND /V "ing "
IF %ERRORLEVEL% EQU 0 RD /S /Q C:\TMPPACKDIR
ECHO Renaming new file
RENAME *.7z *.CB7
ECHO Removing original file
DEL "%%I"
ECHO File %%I is done
)
)
REM del /f/q "%~0" | exit
Yes, the problem is in the code portion between cd C:\TMPPACKDIR\%%~nI\ and pause. You are trying to set a for variable reference %%N, which does not work. You need to use a normal environment variable instead, like NAME, for example; you can only do sub-string expansion (like ~-2 in your code) using normal environment variables. In addition, since you are setting and reading the same environment variable within a single block of code, you need to use delayed expansion; otherwise, you would always receive the value present when the entire block is read.
The code portion should look like this:
cd /D "C:\TMPPACKDIR\%%~nI"
for /F "delims=" %%P in ('dir /B *.JPG, *.PNG, *.BMP') do (
set "FILE=C:\TMPPACKDIR\%%~nI\%%P"
set "NAME=00%%~nP"
setlocal EnableDelayedExpansion
set "NAME=!NAME:~-2!"
rename "!FILE!" "!NAME!%%~xP"
endlocal
)
pause
I've removed some unnecessary stuff and made a few changes, (the main error being that which aschipfl has already identified).
FOR /F "DELIMS=" %%F IN ('DIR/AD/S/B') DO (
PUSHD "%%F"
IF EXIST *.cbr REN *.cbr *.rar
IF EXIST *.cbz REN *.cbz *.zip
IF EXIST *.cb7 REN *.cb7 *.7z
FOR %%I IN (*.RAR, *.ZIP *.7Z) DO (
ECHO Extracting %%I...
"%ProgramFiles%\7-Zip\7z.exe" e "%%I" -o"C:\TMPPACKDIR\*" -y
PUSHD "C:\TMPPACKDIR\%%~nI"
FOR %%P IN (*.JPG, *.PNG, *.BMP) DO (
SET "_N=100%%~nP"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "_N=!_N:~-2!"
REN "%%P" "!_N!%%~xP"
ENDLOCAL
)
POPD
ECHO Repacking
"%ProgramFiles%\7-Zip\7z.exe" a -t7z "%%~nI.7z" "C:\TMPPACKDIR\%%~nI*" -mx=9
IF NOT ERRORLEVEL 1 RD/S/Q "C:\TMPPACKDIR\%%~nI"
ECHO Renaming new file
REN "%%~nI.7z" "%%~nI.CB7"
ECHO Removing original file
DEL "%%I"
ECHO File %%I is done
)
POPD
)
Things to look into:Can 7z.exe not just extract .cbr, .cbz & .cb7 directly without renaming them first. In the same way, when repacking once you've provided the file type, -t7z can the file not be given the name "%%~nI.CB7" directly instead of later renaming it.
I need help creating a batch script that will add the filename to the first line of every .csv within all subfolders. The batch file will be in the mainfolder. The same folder will contain several subfolders, each containing a large amount of .csv files. I need the files to stay within their respective folders. My goal is to add this to another working script I have that merges all files within a subfolder into a single .csv. This will provide a way to navigate through the merged file. I found some similar posts, but they weren't quite what I was looking for. This is the closest thing I could find but the delimiter stuff is throwing me off Batch file to Write Filename to first line
File Structure Example:
C:\MainFolder\batch_script.bat
C:\MainFolder\SubFolder1\csv1.csv
C:\MainFolder\SubFolder1\csv2.csv
C:\MainFolder\SubFolder2\csv3.csv
C:\MainFolder\SubFolder2\csv4.csv
File Contents before running script
csv1.csv:
This is the content of csv1.csv
csv2.csv:
This is the content of csv2.csv
csv3.csv:
This is the content of csv3.csv
csv4.csv:
This is the content of csv4.csv
File Contents after running script:
csv1.csv:
csv1.csv
This is the content of csv1.csv
csv2.csv:
csv2.csv
This is the content of csv2.csv
csv3.csv:
csv3.csv
This is the content of csv3.csv
csv4.csv:
csv4.csv
This is the content of csv4.csv
P.S.
I also found this code on another website but I'm not sure how I would make it loop through the different subfolders
FOR /F "usebackq tokens=1" %%i IN (`DIR /B`) DO (
ECHO %%i >> %1
TYPE %%i >> %1
)
#echo off
setlocal enableextensions disabledelayedexpansion
for /r %%a in (*.csv) do (
set /p "firstLine=" < "%%~fa"
setlocal enabledelayedexpansion
for /f "delims=" %%b in (".!firstLine!") do endlocal & if not "%%~b"==".%%~nxa" (
( echo %%~nxa
type "%%~fa"
) > "%%~fa.new"
move /y "%%~fa.new" "%%~fa" >nul
)
)
What it does is generate a new file with the name of the csv as the first line, appends the csv to the new file and moves the new file over the csv. In the process, it tests if the content of the first line is the same as the name of the csv to avoid reinclusion of the filename on each run of the batch file.
edited to adapt to comments - As the process will not be run more than once for set of csv files, the full code can be reduced to
#echo off
setlocal enableextensions disabledelayedexpansion
for /r %%a in (*.csv) do (
( echo %%~nxa
type "%%~fa"
) > "%%~fa.new"
move /y "%%~fa.new" "%%~fa" >nul
)
Try this:
for /r %%a in (*.csv) do (
copy /y "%%~a" "%temp%\%%~na"
Echo %%~na > "%%~a"
for /f "usebackq" %%b in ("%temp%\%%~na") do Echo %%b >> "%%~a"
del "%temp%\%%~na"
)
And that should do what you want it to. I would test it out first if you could.
This should create an all.csv in every folder in the tree under the C:\MainFolder and add the filename before the contents of each CSV file.
The filename will contain the full path but that can easily be changed if needed.
#echo off
for /d /r "C:\MainFolder\" %%a in (*) do (
pushd "%%a"
(for %%b in (*.csv) do (
echo %%b
type "%%b"
)
)>all.tmp
ren all.tmp all.csv
popd
)
pause
I'm trying to copy some files from one directory to two other directories, using batch.
First i'm making 3 directories and after that, i want to copy the following files to backup1 and backup2.
The files are named 010101.txt - 300101.txt (To backup1) and 010102.txt - 300102.txt (backup2).
mkdir backup1
mkdir backup2
mkdir backup3
copy 1.txt C:\User\Test\Backup1
copy 2.txt C:\User\Test\Backup2
I guess i have to use wildcard somehow, but if i write ?????1.txt and ?????2.txt i get an syntex error.
Try this out:
#echo off
setlocal enabledelayedexpansion
cd /d "C:\Temp\copytest"
set "b1=C:\Temp\Backup1"
set "b2=C:\Temp\Backup2"
for /l %%a in (1,1,300102) do (
set num=%%a
if %%a GTR 10000 if %%a LSS 100000 set num=0%%a
if !num:~-1! EQU 1 (
if exist !num!.txt echo copy !num!.txt %b1%
) ELSE (
if !num:~-1! EQU 2 (
if exist !num!.txt echo copy !num!.txt %b2%
)
)
)
Change paths where applicable. Remove the echos after verifying the output is correct to do the actual copy.
Edit: Simpler way
Copy *1.txt "C:\User\Test\Backup1"
Copy *2.txt "C:\User\Test\Backup2"
#ECHO OFF
SETLOCAL
SET "sourcedir=."
FOR %%b IN (1 2) DO (
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*.txt" ^| find /i "%%b.txt" '
) DO (
XCOPY "%sourcedir%\%%a" "c:\user\test\backup%%b\" >nul
)
)
GOTO :EOF
I've assumed you want all files in the directory that contain 1.txt to be copied to ...\backup1 and those that contain 2.txt to ...\backup2.
I used my current directory for testing. You'd need to change the value assigned to 'sourcedir' to suit yourself.
Note that the xcopy will create the destination directory if necessary.
I've seen some scripts examples over SO, but none of them seems to provide examples of how to read filenames from a .txt list.
This example is good, so as to copy all files from A to B folder
xcopy c:\olddir\*.java c:\newdir /D /E /Q /Y
But I need something like the next, where I can fill actually the source and destination folder:
#echo off
set src_folder = c:\whatever\*.*
set dst_folder = c:\foo
xcopy /S/E/U %src_folder% %dst_folder%
And instead of src_folder = c:\whatever\*.*, those *.* need to be list of files read from a txt file.
File-list.txt (example)
file1.pds
filex.pbd
blah1.xls
Could someone suggest me how to do it?
Given your list of file names in a file called File-list.txt, the following lines should do what you want:
#echo off
set src_folder=c:\whatever
set dst_folder=c:\target
for /f "tokens=*" %%i in (File-list.txt) DO (
xcopy /S/E "%src_folder%\%%i" "%dst_folder%"
)
I just tried to use Frank Bollack and sparrowt's answer, but without success because it included a /U switch for xcopy. It's my understanding that /U means that the files will only be copied if they already exist in the destination which wasn't the case for me and doesn't appear to be the case for the original questioner. It may have meant to have been a /V for verify, which would make more sense.
Removing the /U switch fixed the problem.
#echo off
set src_folder=c:\whatever
set dst_folder=c:\target
for /f "tokens=*" %%i in (File-list.txt) DO (
xcopy /S/E "%src_folder%\%%i" "%dst_folder%"
)
This will do it:
#echo off
set src_folder=c:\batch
set dst_folder=c:\batch\destination
set file_list=c:\batch\file_list.txt
if not exist "%dst_folder%" mkdir "%dst_folder%"
for /f "delims=" %%f in (%file_list%) do (
xcopy "%src_folder%\%%f" "%dst_folder%\"
)
The following will copy files from a list and preserve the directory structure. Useful when you need to compress files which have been changed in a range of Git/SVN commits¹, for example. It will also deal with spaces in the directory/file names, and works with both relative and absolute paths:
(based on this question: How to expand two local variables inside a for loop in a batch file)
#echo off
setlocal enabledelayedexpansion
set "source=input dir"
set "target=output dir"
for /f "tokens=* usebackq" %%A in ("file_list.txt") do (
set "FILE=%%A"
set "dest_file_full=%target%\!FILE:%source%=!"
set "dest_file_filename=%%~nxA"
call set "dest_file_dir=%%dest_file_full:!dest_file_filename!=%%"
if not exist "!dest_file_dir!" (
md "!dest_file_dir!"
)
set "source_file_full=%source%\!FILE:%source%=!"
copy "!source_file_full!" "!dest_file_dir!"
)
pause
Note that if your file list has absolute paths, you must set source as an absolute path as well.
[¹] if using Git, see: Export only modified and added files with folder structure in Git
This will also keep the files original file directory:
#echo off
set src_folder=c:\whatever
set dst_folder=c:\target
set file_list=C:\file_list.txt
for /f "tokens=*" %%i in (%file_list%) DO (
echo f | xcopy /E /C /R /Y "%src_folder%\%%i" "%dst_folder%\%%i"
)
Also can use robocopy and Not use for loop with xcopy - can parse list of files in argument.
robocopy Source_folder Destination_folder [files_to_copy] [options]
Files to copy it's string with Space delimiter.
For example:
robocopy . "d:\my folder" *.txt "my file one.cpp" file2.cpp
robocopy "d:\F 15" "d:\backup\F 15" /E