Batch File to rename filenames from multiple directories - batch-file

I have multiple *.jpg files located in folders within a main root folder. I'm after a simple batch file that will rename all the files to it's foldername. For example:
Orphan
---Gambia
------GAM001
---------G123.jpg
---------G456.jpg
---------GX12.jpg
------GAM002
---------G789.jpg
---------G012.jpg
---------G112.jpg
And i would like it to look like this:
Orphan
---Gambia
------GAM001
---------GAM001.jpg
---------GAM001 (1).jpg
---------GAM001 (2).jpg
------GAM002
---------GAM002.jpg
---------GAM002 (1).jpg
---------GAM002 (2).jpg
So i'm after a batch file that I can run from the Main Root folder.
Sorry in advance as I am new to all of this and I thought I would give it a go into something that I am finding very interesting!
Thanks in advance

#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir\orphan"
FOR /d /r "%sourcedir%" %%a IN (*) DO (
PUSHD "%%a"
FOR /f "delims=" %%f IN (
'dir /b /a-d /o-n "%%~nxa*.jpg" 2^>nul'
) DO REN "%%f" "%%f.jpg"
SET /a count=0
FOR /f "delims=" %%f IN (
'dir /b /a-d "*.jpg" 2^>nul'
) DO ECHO REN "%%f" "%%~nxa (!count!).jpg"&SET /a count +=1
IF EXIST "%%~nxa (0).jpg" ECHO REN "%%~nxa (0).jpg" "%%~nxa.jpg"
POPD
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
First step is to process the names of the directories, recursively into %%a. These are then pushed (which switches to the nominated directory, %%) and the main process executed before executing a pop to restore the original directory.
The main process first reads the directory for (dirnameanything.jpg) and sorts in reverse-name order to ensure the longest name is first. Then any names found are renamed with an extra ".jpg" This means that if the directory has already been processed, (eg) GAM002.jpg may exist, so it is renamed gam002.jpg.jpg and hence gam002.jpg will not exist after this first rename - and the same goes for gam002 (1) - it is now gam002 (1).jpg.jpg. Even if gam002.jpg.jpg already existed, this method is safe because the renaming is performed in reverse-name order, so gam002.jpg.jpg would have been renamed gam002.jpg.jpg.jpg before an attempt is made to rename gam002.jpg to gam002.jpg.jpg
Next step is the real rename sequence. Each .jpg is listed and then processed, so the original list of files is renamed, avoiding the problem with encountering an already-renamed file. Each one is simply renamed with an increasing count in parentheses after the name of the parent directory.
Finally, "parentdirectoryname (0).jpg" is renamed to "parentdirectoryname.jpg" and all is complete.

Related

Create Folder and SubFolder based on file name using batch file

Coding is not my speciality but I have come across a problem and google search has guided me to using batch file process in solving it. Essentially I have a couple of thousands of files that need to be moved into folders and they have a very simple file structure, listed below:
UK--London--Filename.pdf
UK--London--Filename2.pdf
UK--Manchester--Filename3.pdf
UK--Liverpool--Filename4.pdf
UK--Chester--Filename5.pdf
I would like the script to:
1. Pick up the first "--" check if the folder exists, if not create it
2. Pick up the second "--" check if the folder exists, if not create it
3. As there might be more than two "--", ignore the rest
4. Move file into the subfolder
To that end, the output should be some like (note "FILETEST" is the folder I am using to test the script):
C:\FILETEST\UK\London\UK--London--Filename.pdf
C:\FILETEST\UK\London\UK--London--Filename2.pdf
C:\FILETEST\UK\Manchester\UK--Manchester--Filename3.pdf
C:\FILETEST\UK\Liverpool\UK--Liverpool--Filename4.pdf
C:\FILETEST\UK\Chester\UK--Chester--Filename5.pdf
I have had an attempt to re-using a script from another question in stackoverflow (Batch create folders based on part of file name and move files into that folder). I understand that it would not do exactly what I need, but cant seem to get any output.
#ECHO OFF
SETLOCAL
SET "sourcedir=c:\FILETEST"
PUSHD %sourcedir%
FOR /f "tokens=1*delims=--" %%a IN (
'dir /b /a-d *.*.*'
) DO (
ECHO MD %%a
ECHO MOVE "%%a.%%b" --\%%a\
)
POPD
GOTO :EOF
Apologies for any headaches caused, I am hoping this is a simple one to solve.
Thank you,
Panos
#ECHO OFF
SETLOCAL
SET "sourcedir=c:\FILETEST"
PUSHD %sourcedir%
FOR /f "tokens=1,2*delims=-" %%a IN (
'dir /b /a-d *--*--*.*'
) DO if "%%c" neq "" (
ECHO MD "%%a"
ECHO MD "%%a\%%b"
ECHO MOVE "%%a--%%b--%%c" ".\%%a\%%b\"
)
POPD
GOTO :EOF
Read the directory list of files in the current directory, (/a-d = no directorynames) that match *--*--*. Tokenise so that %%a acquires the part before the first --sequence, %%b the second and %%c the remainder.
If %%c is not empty then make the directories ".\%%a" and ".\%%a\%%b" (quoted because any spaces in the name would otherwise be seen as "create two directories") then move the file, again quoted for the same reason.
Note that each character individually between delims= and the close-quote is a delimiter - a delimiter-string is not supported. Consequently, this code will pick up - as well as --- and any other sequence of - and try to process it. You could gate the create/move further by adding if exist "%%a--%%b--%%c" directly after the if "%%c" neq ""before the (.
The md will create a directory if the target name does not already exist, and produce an error-message if it already exists. To suppress the error message, append 2>nul to the md lines.

batch file rename files in folder

I have multiple text files in a folder that I am searching the content for and renaming the found files but having a problem. When I run the batch it renames all the found files to the same filename. So if it finds 3 files with the string in them it renames all of them to the same file. Still kinda new to this stuff. I am trying to find the string "test1" inside all the text files and then rename the files found to test1.txt, test1 (2).txt, etc.
#ECHO OFF
#SETLOCAL enableextensions disabledelayedexpansion
SET "sourcedir=C:\test"
SET "searchfor=test1"
FOR /f "delims=" %%a IN ('findstr /m /L /c:"%searchfor%" "%sourcedir%\*.txt"') DO (
REN "%%a" "%searchfor%.txt"
)
change
REN "%%a" "%searchfor%.txt"
to
if exist "%searchfor%.txt" (
set "renamed="
for /L %%r in (1,1,100) do if not defined renamed if not exist "%searchfor% (%%r).txt" REN "%%a" "%searchfor% (%%r).txt"&set "renamed=%%r"
) else (
REN "%%a" "%searchfor%.txt"
)
which will for each filename-to-be-changed first detect whether %searchfor%.txt exists, and rename the target file if not. If %searchfor%.txt exists, then set the renamed flag to nothing and loop for %%r = 1 to 100 by steps of 1. If the filename %searchfor% (%%r).txt does not exist, then do the rename and set renamed to (well - any value other than nothing will do - %%r is convenient). Since renamed is now defined, if not defined will be false, so no further rename attempts will be made for that target filename.
(untested)
Note - the syntax is important. Don't try to break the statements over many lines or alter the positions of the parentheses. Just cut-and-paste.
Tip:
Instead of ren use echo ren which will simply REPORT the proposed rename. Obviously, since the file won't actually be renamed, the procedure will report the same new name. Then manually create %searchfor%.txt and try again. Then manually create %searchfor% (1).txt and try yet again. You'll see the proposed new name change. After testing in this manner, change each echo ren to ren and all should proceed smoothly.
(perform tests on a copy with a small number of "hits" to avoid confusion)

CMD deleting folder recursively (i.e. same folder name in multiple locations)

Due to a Dreamweaver setting mess-up, we've had thousands of "_notes" folders pop up in our websites dev & qa areas. There's too many to delete through Windows Explorer - everything just locks up - so I was hoping to run a batch script to sort it out for us once and for all. The problem is I'm not entirely sure that "rd /S" will do what I want.
My understanding is that rd /S will look recursively in the folder I tell it, so if I say:
rd /S r:/<siteName>/_notes/
then it will just look in the _notes folder and delete what's in there and then try to move further down that tree. What I need is a script that would take into account things like the following:
r:/<siteName>/_notes/
r:/<siteName/<someFolder>/_notes/
r:/<siteName/<someOtherFolder>/_notes/
r:/<siteName/<someFolder>/<someSubFolder>/_notes/
r:/<siteName/<someFolder>/<iThinkIveMadeMyPoint>/_notes/
Hope I made sense...
I found this in another thread, but it doesn't work with folders with a . in the name, so it's no use for site names...
#Echo OFF
REM Important that Delayed Expansion is Enabled
setlocal enabledelayedexpansion
REM This sets what folder the batch is looking for and the root in which it starts the search:
set /p foldername=Please enter the foldername you want to delete:
set /p root=Please enter the root directory (ex: C:\TestFolder)
REM Checks each directory in the given root
FOR /R %root% %%A IN (.) DO (
if '%%A'=='' goto end
REM Correctly parses info for executing the loop and RM functions
set dir="%%A"
set dir=!dir:.=!
set directory=%%A
set directory=!directory::=!
set directory=!directory:\=;!
REM Checks each directory
for /f "tokens=* delims=;" %%P in ("!directory!") do call :loop %%P)
REM After each directory is checked the batch will allow you to see folders deleted.
:end
pause
endlocal
exit
REM This loop checks each folder inside the directory for the specified folder name. This allows you to check multiple nested directories.
:loop
if '%1'=='' goto endloop
if '%1'=='%foldername%' (
rd /S /Q !dir!
echo !dir! was deleted.
)
SHIFT
goto :loop
:endloop
read HELP FOR, HELP SET and HELP IF
note that FOR /D /R will recursively walk the directory tree.
note also that %~na is the funny syntax to extract the name part of a full path.
so, putting this little pieces togethere, try this command on the command line
for /d /r %a in (*) do #if %~na==_notes #echo rd %a
after careful testing, remove the echo command.
This command has worked for me and I hope this could help. Switch to the common root folder, and type in CMD:
for /d /r . %d in (<folder name>) do #if exist "%d" rd /s/q "%d"
Change the to the name of folder you want to remove. Then all children folders with this name would be removed.

Batch Script to create folder based on name, add to existing code

The code below works fine, here is a list of it's functions:
It moves files based on the fist 4 characters to a pre-created folder with the same first 4 characters
If the folder does not exist, it will not move the file, as there is no folder with the same fist 4 chars.
#echo on
setlocal enabledelayedexpansion
cls
pushd R:\Contracts\Sites
for /f "tokens=*" %%1 in ('dir /a-d /b *') do (
set filename=%%1&set dirname=!filename:~0,4!
for /f "tokens=*" %%A in ('dir /ad /b') do (
set dirid=%%A & set dirid=!dirid:~0,4!
if "!dirid!" equ "!dirname!" move %%1 %%A
)
)
I would like to add one extra function to this code please. Pleas have a look at the example below.
I have 5 files
X32A-test.docx or X32A-test.pptx (there will only be one docx or pptx, "NEVER two with the same name")
X32A-test.pdf
X32A-test.avi
X32A-test-eng.sub
X32A-test-small.jpg
I would like the code to CREATE a folder if it does not exist, based on the file name if it has the extension docx or pptx.
So with the above example it would create a folder named: "X32A-test". Then all the other files with "X32A" in the front of the name will be moved to that newly created folder "X32A-test".
I hope it is clear enough. If not please ask me for more information.
Thank you
It is much simpler and more efficient to use the simple FOR instead of FOR /F in your case.
And rather than looping through every file and moving them individually, it is easier and more efficient to use wildcards.
The first loop finds the .pptx and .docx files and creates folders as needed
The second loop finds all the directories and moves all files that start with the directory name into the directory.
#echo on
setlocal enableDelayedExpansion
cls
pushd R:\Contracts\Sites
for %%F in (*.docx *.pptx) do (
set "folder=%%F"
2>nul md !folder:~0,4!
)
for /d %%F in (*) do move %%F* %%F
popd
If needed, you can protect yourself against directory names shorter than length 4.
#echo on
setlocal enableDelayedExpansion
cls
pushd R:\Contracts\Sites
for %%F in (*.docx *.pptx) do (
set "folder=%%F"
set folder=!folder:~0,4!
if !folder:~0,3! neq !folder! 2>nul md !folder!
)
for /d %%F in (????) do (
set "folder=%%F"
if "!folder:~0,3!" neq "%%F" move %%F* %%F
)
popd
Note that this solution may fail if a file name contains !. If that arises then you need to toggle delayed expansion on and off within the loop(s).
I can see the entire process (including the part already implemented) like this:
All the files that are not yet in their "home" directories are moved there.
For all .docx and .pptx files left, create directories based on the files' names.
Obviously, the step #2 creates new "homes" and those will still be "uninhabited" this far. So all that is left to do now is to repeat the step #1.
So I would probably reorganised your process and, with the additional requirement, it could be implemented this way:
…
PUSHD your_root_directory
FOR /D %%D IN (*) DO (
CALL :movefiles "%%D"
)
FOR %%F in (*.docx *.pptx) DO (
MKDIR "%%~dpnF"
CALL :movefiles "%%~dpnF"
)
…
GOTO :EOF
:movefiles
SET "dirname=%~n1"
SET "mask=%dirname:~0,4%*"
MOVE "%~dp1%mask%" %1
Note: The steps #2 and #3 could be either implemented as separate loops or combined in one. The above script uses the latter approach.
You can use negative offsets in the !var:~offset,len! evaluation as follows:
set fspec=X32A-test.docx
echo !fspec:~-10!
echo !fspec:~0,-10!
That second line above gives you -test.docx and you can simply check that against your two desired possibilities with an if statement (or two).
Then you can use the third line to get the rest of the name for creating a directory.
The following example script shows how this could be done:
#setlocal enableextensions enabledelayedexpansion
#echo off
set fspec=X32A-test.docx
set bit1=!fspec:~-10!
set bit2=!fspec:~0,-10!
if .!bit1!.==.-test.docx. echo mkdir !bit2!
if .!bit1!.==.-test.pptx. echo mkdir !bit2!
endlocal
I'm echoing the mkdir command rather than executing it so you need to take out the echo. You'll also need to integrate the set and if statements into your loop but, based on what you have so far, you should have little trouble with that.
If, as you seem to indicate in a comment, the first four characters are the key and the last five decide on whether to make the directory, as in:
x32s-test.docx
a21w-production.pptx
xxxx-whatever_the_blazes_you_want.some_other_rubbish.docx
Then you're really only interested in the first four and last five:
#setlocal enableextensions enabledelayedexpansion
#echo off
set fspec=a12b-whatever_the_blazes_you_want.some_other_rubbish.docx
set bit1=!fspec:~-5!
set bit2=!fspec:~0,4!
if .!bit1!.==..docx. echo mkdir !bit2!
if .!bit1!.==..pptx. echo mkdir !bit2!
endlocal
This checks the correct extensions and outputs:
mkdir a12b
as expected.

Iterating through folders and files in batch file?

Here's my situation. A project has as objective to migrate some attachments to another system.
These attachments will be located to a parent folder, let's say "Folder 0" (see this question's diagram for better understanding), and they will be zipped/compressed.
I want my batch script to be called like so:
BatchScript.bat "c:\temp\usd\Folder 0"
I'm using 7za.exe as the command line extraction tool.
What I want my batch script to do is to iterate through the "Folder 0"'s subfolders, and extract all of the containing ZIP files into their respective folder.
It is obligatory that the files extracted are in the same folder as their respective ZIP files. So, files contained in "File 1.zip" are needed in "Folder 1" and so forth.
I have read about the FOR...DO command on Windows XP Professional Product Documentation - Using Batch Files.
Here's my script:
#ECHO OFF
FOR /D %folder IN (%%rootFolderCmdLnParam) DO
FOR %zippedFile IN (*.zip) DO 7za.exe e %zippedFile
I guess that I would also need to change the actual directory before calling 7za.exe e %zippedFile for file extraction, but I can't figure out how in this batch file (through I know how in command line, and even if I know it is the same instruction "cd").
EDIT #1
I have already received some tips on ServerFault to the same question. Please see the answers at this link.
However, it extracted from the root (C:), and not from the given in parameter folder.
Anyone has an idea?
EDIT #2
It seems that batch script doesn't handle folder and file names containing a space character adequately. Can anyone confirm what I think?
EDIT #3
I need it to be fully recursive, since I don't know the directory structure against which this will be used.
EDIT #4.a
With #aphoria's solution, I'm almost there! The only problem is that it takes let's say File5.zip, retrieve the filename only to get File5, creates a subfolder File5 and extract the File5.zip to File5 subfolder, then, it wants to create a File5 subfolder in Folder 1, where it should instead want to create File1 subfolder, to stick with my example.
EDIT #4.b
As required, here's the code as it currently look:
#echo off
setlocal enableextensions enabledelayedexpansion
rem
rem Display instructions when no parameter is given.
rem
if "%1" equ "" (
echo Syntaxe : od.bat ^<directory mask>^
echo Exemple : od.bat *
goto :Eof
)
rem
rem Setting the PATH environment variable for this batch file for accessing 7za.exe.
rem
path=c:\temp;%PATH%
rem
rem Removing quotes from the given command line parameter path.
rem
set root=%1
set root=%root:~%1
set root=%root:~0,-1%
rem Searching directory structure from root for subfolders and zipfiles, then extracting the zipfiles into a subfolder of the same name as the zipfile.
for /F "delims==" %%d in ('dir /ogne /ad /b /s %root%') do (
echo Traitement du dossier : "%%d"
for /F "delims==" %%f in ('dir /b "%%d\*.zip"') do (
rem Getting filename without extension.
set subfolder=~n%f
mkdir "%%d\%subfolder%"
rem Extracting zipfile content to the newly created folder.
7za.exe e "%%d\%%f" -o"%%d\%subfolder%"
)
)
:Eof
endlocal
Ideas anyone?
My guess is that it digs one directory hierarchy at a time. Here's the deal. Consider we have a Folder A in Folder 1 (Folder 1\Folder A), then, it searches from Folder 1 through Folder 5, and comes back to Folder 1\Folder A, where the %subfolder% variable sticks with its last value.
Anyone's help is gratefully appreciated.
I'm not very familiar with the 7zip command-line options, so you will need to figure out the exact command for that, but the script below will take a fully specified path (spaces allowed) and print out the the folder name and .zip files contained within it.
#ECHO OFF
REM
REM Remove the double quotes from the front and end of the root path
REM
SET ROOT=%1
SET ROOT=%ROOT:~1%
SET ROOT=%ROOT:~0,-1%
ECHO %ROOT%
FOR /F "DELIMS==" %%d in ('DIR "%ROOT%" /AD /B') DO (
ECHO %%d
FOR /F "DELIMS==" %%f in ('DIR "%ROOT%\%%d\*.zip" /B') DO (
ECHO %%f
)
)
Run it like this:
MyScript.CMD "c:\temp\usd\Folder 0"
You should get output similar to this:
Folder A
File 1.zip
File 2.zip
Folder B
File 1.zip
File 2.zip
UPDATE
The code below will extract Folder A\File 1.zip to a new folder Folder A\File 1.
A few things to keep in mind:
In the first FOR loop, you need to have %ROOT% enclosed in double quotes to handle folders with spaces in the name.
Since you're SETting a variable inside the second FOR, you need to put SETLOCAL ENABLEDELAYEDEXPANSION at the beginning. Then, reference the variable using ! (for example, !subfolder!) to force expansion at runtime.
This line of your code set subfolder=~n%f should be this set subfolder=%%~nf
I put ECHO in front of the MKDIR and 7za.exe commands to test. Once you are sure it is doing what you want, remove the ECHO statement.
Here is the code:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
REM
REM Remove the double quotes from the front and end of the root path
REM
SET ROOT=%1
SET ROOT=%ROOT:~1%
SET ROOT=%ROOT:~0,-1%
ECHO %ROOT%
REM Searching directory structure from root for subfolders and zipfiles,
REM then extracting the zipfiles into a subfolder of the same name as the zipfile.
FOR /F "delims==" %%d IN ('dir /ogne /ad /b /s "%ROOT%"') DO (
ECHO Traitement du dossier : "%%d"
FOR /F "delims==" %%f IN ('dir /b "%%d\*.zip"') DO (
REM Getting filename without extension.
SET subfolder=%%~nf
ECHO mkdir "%%d\!subfolder!"
REM Extracting zipfile content to the newly created folder.
ECHO 7za.exe e "%%d\%%f" -o"%%d\!subfolder!"
)
)
ENDLOCAL

Resources