Search for substring in folder names - batch-file

I hope someone can help me with my problem.
There is a directory containing folders for every order, e.g.
L:\Med_Department\Orders\
L:\Med_Department\Orders\T0012345_AB100_CustomerA_site2
L:\Med_Department\Orders\T0012346_CD350-CustomerB site1
...
How can I get the full name of a folder by searching for the order number.
When I enter the order number for example:
T0012345
,
I want the script to store
T0012345_AB100_CustomerA_site2
in a variable so I can use it to create the folder for my new project instead of the order number.
The order number is unique and has the format Txxxxxxx . The rest of the folder name can be separated by underscore, blank space or other characters.
If the order number is not found (e.g. order number not entered correctly) the user should enter the order number again.
This is what I achieved so far.
I enter the order number and the script copies a template folder into my projects directory with the order number as folder name.
#Echo off
rem directories
set template= "N:\Documentation\New_folder_OrderNo-Type-Customer-site"
set dirOrder= "L:\Med_Department\Orders\"
SET dirProjects= "Z:\Projects\2016\"
rem input Order No.
echo Please enter the order number?
echo.
set /p OrderNo=OrderNo:
rem target directory
set dirNewProject=%dirProjects%%OrderNo%\
echo %dirnewProject%
pause
rem copy content from template into target directory
xcopy %template% %dirNewProject% /S /E /C /H /O /R /Y /D /V
rem open target directory
explorer %dirNewProject%
;exit
Thanks in advance.

something like this:
#Echo off
rem directories
set template= "N:\Documentation\New_folder_OrderNo-Type-Customer-site"
set dirOrder = "L:\Med_Department\Orders\"
SET dirProjects= "Z:\Projects\2016\"
:again
rem input Order No.
echo Please enter the order number?
echo.
set /p OrderNo=OrderNo:
if not exist "%dirOrder%%OrderNo%\" (
echo order %OrderNo% not found
goto :again
)
:: the rest of the script
:: ...
?

use a for to get the output of a command. Use dir with proper switches to do a wildcard search (Note: with dir wildcards do only work within the very last element of a path).
:again
set /p "OrderNo=OrderNo: "
set "folder=none"
for /f "delims=" %%a in ('dir /s /ad /b %dirOrder%%OrderNo%*') do set folder=%%a
if %folder% == none goto :again
echo found: %folder%
see for /? and dir /? for details

You can simply use for /D against the pattern %OrderNo%*. If there is folder whose name starts with %OrderNo% (there should be one only, if I got it right), dirNewProject is going to hold its path; if there is none, the variable is going to be empty. You can chek if [not] defined dirNewProject afterwards and jump to a :LABEL contitionally:
rem (skipping data entry part of script)
rem directory
set "dirNewProject="
for /D %%I in ("%dirProjects%\%OrderNo%*") do set "dirNewProject=%%I"
if not defined dirNewProject goto :LABEL
rem (skipping file copy part of script)

Example...(Untested)
#Echo Off
SetLocal
Rem directories
(Set template=N:\Documentation\New_folder_OrderNo-Type-Customer-site)
(Set dirOrder=L:\Med_Department\Orders)
(Set dirProjects=Z:\Projects\2016)
Rem exit if above directories do not exist
For %%a In (template dirOrder dirProjects) Do (If Not Exist "%%%%a%%\" Exit/B)
Rem make search dir current
If /I Not "%CD%" Equ "%dirOrder%" PushD %dirOrder%
:AskNum
Rem input Order No.
Echo(
Echo( Please enter the order number?
Echo(
Set/P "OrderNo=OrderNo: "
For /D %%a In ("%OrderNo%*") Do (Set OrderDir=%%~a)
If Not Defined OrderDir (Choice /C /M "Would you like to try again?"
If Errorlevel 2 Exit/B
GoTo :AskNum)
Rem new project directory
(Set dirNewProject=%dirProjects%\%OrderDir%)
Rem copy content from template to new project directory
If Not Exist "%dirNewProject%\" (
RoboCopy "%template%" "%dirNewProject%" /E /Copy:DATSO)
Rem open new project directory
Explorer "%dirNewProject%"

Related

Batch For /R Results to be set menu choice

need a bit of help with a project.
Scenario :-
Manually migrating PC's to new Domain breaks a piece of software due to the new profile not having the settings from the old user profile - required to make it run. The old profile is called one thing, the new one - something else e.g.
C:\Users\Sue.Barnes.B3209 (old) C:\Users\Susan.Barnes.NGP (new)
Within the %localappdata% of each (old) profile there "maybe" a config file for this software, if the user has used it previously. E.g.
C:\Users\Sue.Barnes.B3209\AppData\Local\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\user.config
Objectives :-
I want to be able to scan through the C:\Users Folder and report back the full path, name & extension of file where it is found, then have the list set in a menu choice where upon input choice will copy the user.config file to the exact same location but in the currently logged on new profile appdata folder.
e.g.
Enumerating List Of User Profiles in the System...
Admin
Public
User
From the Profiles detecting active Configs...
C:\Users\Admin\AppData\Local\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\user.config
C:\Users\Public\AppData\Local\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\user.config
Press any key to continue . . .
However it is at this point I'm out of my depth. I cant seem to be able to create a choices menu of each instance where the file is found. However many are found, I'd like a number to be printed on the screen so I can choose the correct config to copy to the newly set up profile. Simply,
Xcopy /f C:\Users\Sue.Barnes.B3209\AppData\Local\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\user.config
%localappdata%\Acme_Limited\Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh\1.0.0.15\
Current code base :-
echo.
echo Enumerating List Of User Profiles in the System...
echo.
TIMEOUT /T 3 >NUL
dir /b C:\Users
echo.
echo From the Profiles detecting active Configs...
echo.
TIMEOUT /T 3 >NUL
for /R "C:\Users" %%a in (1.0.0.15\user.config*) do (
echo %%~dpnxa
)
)
echo.
pause
Any help be greatly appreciated, thanks
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
set "dontshow=u:\dontshow.txt"
set "configs=u:\configs.txt"
set "profiles=u:\profiles.txt"
:again
echo :>>"%dontshow%"
del "%configs%" >nul 2>nul
del "%profiles%" >nul 2>nul
:: Find all of the "user.config" files having ..\appdata\local\Acme_limited\...1.0.0.15
FOR /f "tokens=1-9delims=\" %%a IN (
'dir /s /b /a-d "%sourcedir%\user.config" '
) DO if /i "%%d"=="appdata" if /i "%%e"=="local" if /i "%%f"=="Acme_Limited" if /i "%%h"=="1.0.0.15" (
rem these are the users' config files that may be copied.
echo %%c|findstr /x /g:"%dontshow%" /i /L >nul
if errorlevel 1 >>"%configs%" echo %%c
)
:: Find all of the user profiles that are not in "dontshow" and do NOT have "user.config" - These are the profiles that may need to be processed
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%" '
) DO (
echo %%a|findstr /x /g:"%dontshow%" /i /L >nul
if errorlevel 1 echo %%a|findstr /x /g:"%configs%" /i /L >nul
if errorlevel 1 >>"%profiles%" echo %%a
)
:: Now we have a list of profiles with "user.config" missing in %profiles%
:: And possible source-profiles in %configs%
:: Show the list of "config missing" profiles
cls
findstr /n /v /L /c:":" "%profiles%"
:reselectd
set "selectiond="
set /p "selectiond=Choose destination profile "
if not defined selectiond goto :eof
for /f "tokens=1*delims=:" %%a in ('findstr /n /v /L /c:":" "%profiles%"') do if "%%a"=="%selectiond%" set "selectiond=%%b"&goto selects
echo Invalid selection
goto reselectd
:selects
for /L %%a in (1,1,4) do echo.
findstr /n /v /L /c:":" "%configs%"
:reselects
set "selections="
set /p "selections=Choose source profile "
if not defined selections goto :eof
for /f "tokens=1*delims=:" %%a in ('findstr /n /v /L /c:":" "%configs%"') do if "%%a"=="%selections%" set "selections=%%b"&goto process
echo Invalid selection
goto reselects
:process
echo Copy from profile "%selections%" to "%selectiond%" ?
choice
if errorlevel 2 goto again
:: Do the copy... just echoed, remove `echo` keyword to activate
ECHO md "%sourcedir%\%selectiond%\appdata\localAcme_Limited\whatever\1.0.0.15"
ECHO copy "%sourcedir%\%selections%\appdata\localAcme_Limited\whatever\1.0.0.15\user.config" "%sourcedir%\%selectiond%\appdata\localAcme_Limited\whatever\1.0.0.15"
choice /M "Add '%selections%' to processed file ? "
if errorlevel 2 goto processedd
>>"%dontshow%" echo %selections%
:processedd
choice /M "Add '%selectiond%' to processed file ? "
if errorlevel 2 goto again
>>"%dontshow%" echo %selectiond%
goto again
Interesting exercise. Lack of information about what Acme.exe_Url_m5l4ujc5t22f3qw0q5uz1dwlfcnrdaoh is about (constant string, change-per-user? What?), though - left as an exercise for OP to resolve.
You would need to change the setting of sourcedir to suit your circumstances. The listing uses a setting that suits my system.
I decided that the key part is the third directory level - the user-id. This approach uses files of user-id, two are temporary and one is permanent - "dontshow.txt" which contains a list of user-ids NOT to show. This can be manually maintained using an editor if required.
So - to start, add a line containing a single colon to the "dontshow" file. This is a dummy which can never match a real user-id and is required because findstr doesn't like an empty dictionary file.
The first step is to find all of the user.config files, and use for /f to process the filenames found, selecting the significant directory-levels. Having excluded any path that does not fit the criteria, the third level contents is matched against the exclusions in "dontshow.txt". If the name found is new, add it to the configs file.
Second verse - same as the first, but this time only looking at the directory names. Note that the entry is made to profiles if the name found is NOT on the dontshow list AND is also NOT on the config list.
Now select a destination profile by listing profiles and appending a prefix linenumber: using findstr. Enter a number (manual entry, unchecked) and then match the line number by using for/f.
Rinse and repeat for the configs file for the source profile.
Display the proposed command, accept a Y/N response then ask whether each name should be added to the dontshow list.
And straight on 'til morning.
Note that responding with Return to any of the set /p commands will exit the batch.

Do operation if a found folder does NOT have another subfolder of the same name

I'm trying to create a batch file script that will compress all subfolders named folder1 within a directory, BUT it should only compress this folder if it does NOT contain another subfolder with the same name.
I am very new to cmd and batch files, and this is also my first post of stack overflow, please let me know if I've failed to give some information that I should!
The bit of pseudo-ish code below hopefully illustrates what I'm trying to accomplish:
#echo off
SETLOCAL EnableDelayedExpansion
FOR /D /R %%G IN (*folder1*) DO (
CD %%G
SET /A compress=true
FOR /D /R %%H IN (*folder1*) DO (
ECHO folder contains another folder of same name, should not be compressed
SET /A compress=false
)
IF !compress!==true (
ECHO Run compression operation on folder
"C:\Program Files (x86)\7-zip\7z.exe" a -tzip "%%G.zip" "%%G\"
)
)
Please ask away if anything seems unclear! I'm really hoping to turn the above into functional code, thank you in advance for any input or thoughts.
#ECHO OFF
SETLOCAL
:: Starting directory
SET "sourcedir=U:\sourcedir"
:: name of directory to compress
SET "targetname=targetdir"
FOR /d /r "%sourcedir%" %%a IN (*) DO (
IF /i "%%~nxa" == "%targetname%" IF NOT EXIST "%%a\%targetname%\." (
ECHO compress %%a
rem temporarily switch to target directory
PUSHD "%%a"
ECHO 7z a -tzip "%%a.zip"
rem back to original directory
POPD
)
)
GOTO :EOF
This should do as you want - it will echo not execute the 7z command.
The if sees whether the "name and extension" portion of the directory-name in %%a matches the target (the /i makes the match case-insensitive). If it matches AND there is a subdirectory with the required name, then the compression portion is executed.
There are two points to consider.
First, the name of the destination ZIP file. As you have written it, the ZIP generated would be folder1.zip in the parent directory. IDK what you want here. This code would do the same, but %%a.zip could be replaced by ..\%targetname%.zip since the pushd/popd changes the current directory to the folder1 directory and .. means the parent directory.
The second matter is whether or not you want to compress ...\folder1\folder1 (which would have a destination ZIP file of ...\folder1\folder1.zip)
Revision given comment:
#ECHO OFF
SETLOCAL
:: Starting directory
SET "sourcedir=U:\sourcedir"
:: name of directory to compress
SET "targetname=targetdir"
REM (
FOR /d /r "%sourcedir%" %%a IN (*) DO IF /i "%%~nxa" NEQ "%targetname%" (
rem calculate parent name in %%~nxp and grandparent in %%~nxg
FOR %%p IN ("%%~dpa.") DO FOR %%g IN ("%%~dpp.") DO (
IF /i "%%~nxp" == "%targetname%" IF /i "%%~nxg" NEQ "%targetname%" (
ECHO child %%~nxa
ECHO parent %%~nxp
ECHO Gparent %%~nxg Gppath=%%~dpg
ECHO compress %%a
rem temporarily switch to target directory
PUSHD "%%a"
ECHO 7z a -tzip "%%a.zip"
ECHO -------------------
rem back to original directory
POPD
)
)
)
GOTO :EOF
It's not that clear what you want to do with a directory named ...\folder1\folder1\something or what the target ZIP file-name should be.
The if in the for /d /r line will ensure that only leaf-names that do not match the target name are processed. The path-name in %%a is then processed into the parent and grandparent portions - note that %%~dp? is the drive+path portion of %%? which terminates \ so appending . to this resolves to effectively removing the terminal \ yielding a "filename".
You appear to want to compress directories that have a parent but not a grandparent named with the target string, hence the innermost if statement.
I've just echoed the various strings available at this point so they may be strung together as required to form your destination ZIP file-name. Note that the pushd/popd bracket ensures that the current directory at the time of the compress is the leaf to be compressed.

Creating List of Folders from File Names

I have a folder containing many files named as such: JBMA_23456.docx, JMRI_21456.docx, CM_22554.docx, QUA_11224.docx. How do I create a sub-folder for each file bearing the same name as the file but without the .docx file extension? Additionally, I want to store the filename only as variables.
For example, I need to create a sub-folder named JBMA_23456 from the document
JBMA_23456.docx. Can anyone point me in teh right direction?
#echo off
for %%A in (*.docx) do if not exist "%%~nA" md "%%~nA"
This creates a folder with the same name as each .docx file.
View modifiers in for /? or in call /?. The n modifier is the name.
Path modifiers:
dpnx is drive, path, name and extension.
Here's an example batch file which attempts to perform the tasks as laid out in your question:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "BaseDir=C:\Users\Compo\Desktop\test"
Set "FileExt=.docx"
For /F "Delims==" %%A In ('Set var[ 2^>Nul') Do Set "%%A="
Set "i=0"
For /F "Delims=" %%A In ('Where "%BaseDir%":*%FileExt% 2^>Nul') Do (Set /A i+=1
Call Set "var[%%i%%]=%%~nA"
If Exist "%%~dpA%%~nA\" (Echo Sub-Folder %%~nA already exists in %BaseDir%
) Else (Set /P "=Creating sub-folder %%~nA in %BaseDir%"<Nul
MD "%%~dpA%%~nA">Nul 2>&1 && (Echo= was successful) || Echo= failed))
Set var[ 2>Nul
Pause
In order to use it, you would first ensure that the directory holding your files, (excluding any trailing backslash), is placed between the = and " on line 4, and the single file extension, (including the leading period, .), similarly on line 5.
It is not entirely clear what you are asking for...
Anyway, here is the code i made
echo off
chcp 65001
cls
for /f "usebackq delims=." %%0 in (`dir /b "*.docx"`) do (
set filename=%%0
md %filename%
)
cmd /k
It creates a new folder for every file. Feel free to ask if this was not what you expected

Making a folder with incrementing number depending on existing folders with same name

I want to make a batch file which creates a folder with an incremented number when there is one already existing with the same name.
For example for a folder called folder something like this:
if exist folder md folder1 if exist folder1 md folder2
What I want is to make another folder with an incremented number at the end when there are already 1 or more folders with the same name (folder1, folder2, ...) and make the code shorter.
This batch code is based on your initial idea:
#echo off
set "Folder=C:\Temp\Test"
if not exist "%Folder%" (
md "%Folder%"
goto EndBatch
)
for /L %%N in (1 1 65534) do (
if not exist "%Folder%%%N" (
md "%Folder%%%N"
goto EndBatch
)
)
:EndBatch
set "Folder="
But this solution is VERY slow with several folders already existing.
Much faster is following batch file:
#echo off
set "Folder=C:\Temp\Test"
if not exist "%Folder%" (
md "%Folder%"
goto EndBatch
)
set "FolderCount=0"
for /F "delims=" %%F in ('dir /AD /B "%Folder%*"') do set /A FolderCount+=1
md "%Folder%%FolderCount%"
set "FolderCount="
:EndBatch
set "Folder="
But this batch file does not really check the folder names. It just counts the number of folders starting with same string and expects that for new folder the next number can be used. This could be a wrong assumption for example with C:\Temp\Test1 deleted and C:\Temp\Test and C:\Temp\Test2 still existing. The batch file above tries to create nevertheless C:\Temp\Test2 in this case.
A better batch file would be therefore this one:
#echo off
setlocal EnableDelayedExpansion
set "ParentFolder=C:\Temp"
set "FolderName=Test"
if not exist "%ParentFolder%\%FolderName%" (
md "%ParentFolder%\%FolderName%"
) else (
set "HighestNumber=0"
for /F "delims=" %%F in ('dir /AD /B "%ParentFolder%\%FolderName%*"') do (
set "NameFolder=%%~F"
set "FolderNumber=!NameFolder:%FolderName%=!"
if !FolderNumber! GTR !HighestNumber! set "HighestNumber=!FolderNumber!"
)
set /A HighestNumber+=1
md "%ParentFolder%\%FolderName%!HighestNumber!"
)
endlocal
It is also fast because also not checking existence of each folder. But it really finds out what is the highest number of all folders starting with same string and creates a new folder with next number.
Note 1: This batch code is also not 100% fail safe. For example a folder C:\Temp\Test_New_15 could be a problem for this batch file expecting only C:\Temp\Test, C:\Temp\Test1, C:\Temp\Test2, ... being found. (Test_New_15 is ignored, but something similar could be a problem.) It would be of course possible to eliminate this problem for example with using additionally findstr on every line returned by dir to check if after string defined by FolderName nothing else than a number is appended.
Note 2: A folder number with a leading 0 is interpreted as octal number. It would be necessary to remove leading zeros if there are folders with 1 or more leading 0 on value of FolderNumber before the if condition.
To understand the codes in the 3 batch files, open a command prompt window, execute the following commands, and read help output in the window for each command.
dir /?
for /?
goto /?
if /?
md /?
set /?
setlocal /?
There are better/faster ways of creating increasing folder names (and some of them are at Mofi`s answer!), but as the indicated criteria is short code, here is an alternative (but as Mofi indicates, this can be a slow solution)
#echo off
setlocal enableextensions disabledelayedexpansion
set "folderName=test"
2>nul (md "%folderName%"||cmd /q /c"for /l %%a in (1 1 100000) do md "%folderName%%%a"&&exit %%a")
if errorlevel 1 set "folderName=%folderName%%errorlevel%"
echo Created %folderName%

Rename folder to a random number

I need a batch script,
I am writing a batch script for renaming a folder to a number and that number should not be the same.. Every time I click the batch file, it should be a random number.
eg:
folder name is "temp"
If I run the bat file that folder name should be change to a random number.
eg:
1st time : folder name after rename can be "34324"<br/>
2nd time : folder name after rename can be "29389"<br/>
.
.
.
.
.
nth time : folder name after rename can be "xxxxx"
please teach me how to do this..
I am a newbie in this field..
This batch file saves the information about the last folder name inside itself. Each time it is run, it retrieves this information. If not found, temp is assumed. If folder does not exist, it is created. If it exists, a new name is searched, the folder is renamed and the information saved inside batch file.
#echo off
setlocal enableextensions disabledelayedexpansion
rem Determine where to work
if "%cd:~-1%"=="\" ( set "where=%cd%" ) else ( set "where=%cd%\" )
rem Determine what to search for in the current file
set "testString=:::set lastName=[0-9][0-9]*"
rem Retrieve the last name used
set "lastName="
for /f "tokens=* delims=:" %%a in ('findstr /r /b /e /c:"%testString%" "%~f0"') do %%a
if not defined lastName set "lastName=temp"
rem If the last folder does not exist, create it and finish
if not exist "%where%%lastName%\" (
mkdir "%where%\%lastName%"
echo(Folder [%lastName%] has been created
goto endProcess
)
rem Search for a new name
;:newNameLoop
set "newName=%random%"
if "%newName%"=="%lastName%" goto newNameLoop
if exist "%where%%newName%" goto newNameLoop
rem Rename the folder to the new name
ren "%where%%lastName%" "%newName%" 2>nul && set "save=1" || set "save="
rem If there were no problems, save the new name in current batch file
if defined save (
for /f "tokens=1,* delims=:" %%a in ('findstr /n /r /b /e /v /c:"%testString%" "%~f0" ^& break ^> "%~f0"') do >>"%~f0" echo(%%b
>>"%~f0" echo(:::set lastName=%newName%
echo Renamed [%lastName%] into [%newName%]
) else (
echo Rename operation failed. Ensure folder is not in use
)
rem End of the process, clean and exit
;:endProcess
endlocal
exit /b
And no, the added semicolon in labels is not a typo error. They (or other character) are needed to avoid problems with the delims=:
I have made this for you:
#echo off
:retry
SET /A test=%RANDOM% * 10000 / 100000 + 1
echo %test%
IF EXIST %~dp0\%test% GOTO retry
md "%~dp0\%test%"
GOTO retry
It's quite quick 100+ folders per second, so watch out.

Resources