Batch extracting specific file types from master directory with many subdirectories - batch-file

I have a quantity of folders with archive files,
Parent folder with subfolder eg
Graphics:
graphics 01012021/file31241.7z
graphics 01022021/file4231.7z
odds and ends 01032022/filejohnny.7z
etc
each folder contains an archive - various names numbers.
each archives contains various files, pdf's txt files invoices and image files.
Generally the images are .jpg named various names.
What I would like to do is batch attack the parent folder to extract an image file/s from the each archive from each sub directory and leave the image in the subdirectory with the archive where it came from. If the archive has multiple images that's fine, I am not targeting a single particular image.
hopefully ending up with something like
Graphics:
graphics 01012021/
file31241.7z
yellowstone.jpg
flintstone.jpg
graphics 01022021/
file4231.7z
martha.jpg
odds and ends 01032022/
filejohnny.7z
artemis.jpg
French toast.png
I would rather avoid if possible extracting all the files separating the images then having to re archive.
What I tried to discover originally was to batch extract the image files to the directory it belongs to, have the image file renamed to its directory name. I didn't get close with a solution, so I think if possible just extracting the image would be fine and I can use a renaming app to do the other I've found bulk rename utility to be just fine once I got my head around it.
You wouldn't think that over the years you would collect so many archives, like small drops they ended up become an ocean full.
I have tried researching stack and seen a lot of examples of how eg 7zip works but I just cant get my head quite around it.
I am due to retire they tell me 65 is the time for the chicken coop, I've been a pencil pusher and mouse skater most of my life in the gfx industry. I used to know what was in each archive but memory is a little how to say... rusty nowadays, I know all my archives have images in them. My life would be a lot easier in the sunset of it to look at the pictures and not have to rack my brains trying to remember what was in the archive itself.
Cheers and ty in advance from the colonies downunder.
Grumpy

I found the solution to my issue, no coding just using an app I've been using for years. Total Commander.
Solution was simple in the end.
I open up Total Commander, do a search for the archive files I want Alt F7 it will list in the right hand frame all my archives .7z .zip whatever you have.
Then you select "feed to list box" found in the bottom right hand corner. Do a Ctrl A then Alt F9 which gives you some options.
You clear unpack specific files from archive to "make sure its blank" then files to unpack tell it what your looking for in my case .jpg (it can be any specific file).
Untick unpack path names if stored with files
tick or untick overwrite existing files
untick unpack each archive to a separate subdir (name of the archive)
Hit ok.
It will then search and find the file/s you are looking for and unpack them in the directory/subdirectory/etc they are found in.
Job done... No coding just using TC.. marvellous app

#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
SET "outfile=%destdir%\outfile.txt"
SET "extensions=bat txt"
SET "archives=7z zip"
CALL :prefix sdexts *. %extensions%
CALL :prefix sdarchives *. %archives%
CALL :prefix dexts . %extensions%
CALL :prefix darchives . %archives%
PUSHD "%sourcedir%"
(
FOR /f "delims=" %%b IN ('dir /b /s /a-d %sdexts% %sdarchives%') DO (
SET "unreported=%%b"
FOR %%o IN (%darchives%) DO IF /i "%%~xb"=="%%o" CALL :procarch%%o&SET "unreported="
IF DEFINED unreported ECHO %%~dpb ^| %%~nxb
)
)>"%outfile%"
popd
GOTO :EOF
:: return %1 with each other argument preceded by '%2'
:prefix
SET "$1=%1="
shift
SET "$2=%~1"
:sdl
SHIFT
IF "%1"=="" SET "%$1%"&GOTO :eof
SET "$1=%$1% %$2%%1"
GOTO sdl
:: Process .7z or .zip archives
:procarch.7z
:procarch.zip
SET "skipme=Y"
FOR /f "delims=" %%e IN ('7z L "%unreported%"') DO (
FOR /f "tokens=3delims= " %%o IN ("%%e") DO (
IF "%%o"=="------------" (
IF DEFINED skipme (SET "skipme=") ELSE (SET "skipme=Y")
) ELSE IF NOT DEFINED skipme ECHO "%%o"|FIND "D" >NUL &IF ERRORLEVEL 1 (
SET "filename=%%e"
FOR /f "delims=" %%y IN ("!filename:~53!") DO (
FOR %%c IN (%dexts%) DO IF /i "%%c"=="%%~xy" ECHO %unreported% ^| %%y
)
)
)
)
GOTO :eof
I've a similar requirement, so I spent a bit of time on this...
The first part simply sets the directories to be used.
I used bat and txt as extensions required for testing. Change as desired - just a space-separated list.
Similarly, I chose to examine .zip and .7z archives. Since 7zip can deal with both, the same subroutine can be used to process both. Other archive types may need different processing.
The code uses dir to locate the files of interest, and dir can take a series of arguments, so the routine :prefix converts the list provided as %3+ to a list in variable %1, each term prefixed by the string at %2.
So - sdexts will become *.bat *.txt and dexts .bat .txt for instance.
Next, switch to the source dir to begin the dir to list the required files. For each name returned in %%b (delims= applies the full name, /b basic list (names only), /s processes subdirectories, /a-d suppresses directorynames) - the flag unreported is set to the filename found then the extension of the filename found is compared to the darchives list. If a match is found, execute the procarch%%o routine is executed and the unreported flag set to empty. Then, if unreported has not been cleared, it's not an archive file, so report it.
procarch%%o will be resolved either procarch.7z or procarch.zip and a routine (actually the same routine) is provided.
The :prefix routine sets $1 to %1=, so for example, sdexts=. Then it shifts the parameter list and sets $2 to the prefix to be placed before each term.
Then shift again. If %1 is not empty, append a space and the prefix in $2 and %1 to $1 and repeat.
When %1 becomes empty, execute the command set "%$1%" and finish, so as $1would then contain the stringsdexts= *.bat *.txt, sdexts` would be set to the list required.
The routine :procarch.7z or procarch.zip (the first simply falls through to the second, so the same processing is executed) sets the flag skipme to non-empty as we need to skip 7z's header data.
%%e acquires each line of the 7z L report in turn. %%o is assigned the third token of the 7z report line. This will be junk up to the line with a series of dashes, then the attribute report for the archived items, then another series of dashes, then junk.
So - if %%o is a string of dashes, simply switch skipme to empty/not empty.
If %%o is not dashes, and skipme is not defined then we are between the two lines of dashes (ie. on an archived item line) so we see whether %%o contains D (which would indicate that this is a directory name, which we do not want to report). If it does not, errorlevel will be set non-zero by the find (output of the find is sent to nul=the æther) filename set to the full report line. We're not interested in the first 54 characters, but the remainder contains the archived filename, so see whether the extension of the filename found is one of interest (in dexts) and if it is, report it.
The ( on the line preceding the for ... %%b matches the )>"%outfile%" and sends all output that would otherwise go to the console to the file named.
And the ^| on the echo lines output a literal | character as | is a special character for cmd and needs to be escaped by ^ to be interpreted as a literal.

To answer your question the task is simple involving For loops with recursion, however to be robust the solution will be complex without knowing how those specific long term possibly mixed, 7zip files are subdivided, thus if a 7zip has itself two sub folders with identical named files you will hit error conditions. I have allowed for that using -aou to auto rename if necessary. however I have not added the folder name to each file as that's an extra step.
#echo off & Title Extract Images from 7z files
set "extractor=C:\Program Files (x86)\7-Zip\7z.exe"
set "archives=*.7z"
set "filetypes=*.png *.jpg *.jpeg *.tif *.tiff"
set "startDir=C:\Users\WDAGUtilityAccount\Desktop"
FOR /R "%startdir%" %%I IN (%archives%) DO ( "%extractor%" e "%%I" -o"%%~dpI" %filetypes% -aou)
You can add extra archive types such as .rar or .zip in the same way I have allowed for different image file types. HOWEVER do test for such variations first otherwise a second run will invoke that autonaming of existing duplicates. You can of course change that -aou to -aos to avoid overwite or remove it as desired.
An alternative approach on windows is that, standard windows.zip files can be navigated and thus kept as compressed folders where a click on each file will open in the default application. Thus only need extraction to the folder when you wish to use a non default app.
The secondary advantage more directly related to your need is that some viewers can read just the images and ignore any other contents (even if they can read text or html) and one I support that reads images in zips is SumatraPDF and although not listed it can open .7Z files to show in the same way
Hence my answer to the posed question is I suggest converting 7zip to standard zip rather than expand them, or use SumatraPDF as default/alternative 7z viewer !!.

Related

How do I copy all files of a nested directory structure into one new directory with adding the recursive path to the file name?

maybe some could give me some help with my issue: students upload their java codes via MS Teams assignments that I want to review (and compare with each other) locally.
It is possible for me as a teacher to do a bulk download of all submissions. Extracting the zip reveals the following structure:
root
student1name
project1
version1
file1.java
maybe also other files like file1.class, myfirstcodepastedinword.doc, screenshotofcode.jpg...
version2 //optional
file1.java
subdir // optional
otherfile.class
nextsubdir
lastfile.txt
...
project2
version1
...
student2name
project1
version1
nextClass.java
.. and so on...
What I am looking for is a litte batch that collects all project-sepecific submissions together in one directory (for being able to do simple comparisons).
For identification, the student's name and all leading subdirectories must be added to the new file name.
So, after calling "collectSubmissions.bat", the result should be a new dir called "Submissions" containing all files as follows:
project1
student1name-version1-file1.java
student1name-version1-file1.class (could by omitted, but too much effort, I will simply ignore this manually)
student1name-version1-myfirstcodeinword.doc
student1name-version1-screenshotofcode.jpg
student1name-version2-file1.java
student1name-version2-subdir-otherfile1.class
student1name-version2-subdir-nextsubdir-lastfile.txt
...
student2name-version1-file1.java
...
project2
student1name-version1-nextClass.java
....
I did some research and tried different approaches (starting How can I recursively copy files of a specific pattern into a single flat folder on Windows?) and found one pretty close to my needs here:
How do I copy files with adding folder name to destination file name?
But only the closest parent directory name is used here. But in my case, there can be multiple nested folders, so I am hoping that someone could give me some advice how to do that.
Thank you so much in advance for your help!
#ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
SET "remove=%sourcedir:\=-%"
FOR /f "delims=" %%b IN ('dir /b /s /a-d "%sourcedir%\*" ') DO (
SET "fullname=%%b"
FOR /f "tokens=1,2*delims=\" %%u IN ("!fullname:%sourcedir%\=!") DO (
MD "%destdir%\%%v" 2>NUL
SET "newname=%%u-%%w"
SET "newname=!newname:\=-!"
COPY "%%b" "%destdir%\%%v\!newname!" >nul
)
)
GOTO :EOF
As to the practicalities (assuming this is intended as an exercise in plagiarism-detection)
A student could make the detection difficult by
Changing the whitespace in the file
Changing variable/method names
Changing the sequence in which methods are defined in the file
Changing the sequence of statements (eg X,Y,Z becomes Z,Y,X where those statements are not interdependent)
Changing the sequence of terms in statements (eg x+3 and 3+x are not identical but produce identical results)
...and others

Nested for in batch executed twice [duplicate]

The command for can be used to enumerate a directory and apply (a) certain command(s) on each item. With the /R the same can be accomplished for a full directory tree.
What happens when the content of the enumerated directory (tree) is changed by the command(s) in the body of the for command?
Supposed we have the directory D:\data with the following content:
file1.txt
file2.txt
file3.txt
The output of for %F in ("*.txt") do echo %F when executed in said directory will reflect the above list obviously.
However, what is the output of the for loop when a command in the for body modifies the content of the directory? For instance, one of the files in the list is deleted, let's say file3.txt, before it is actually iterated? Or if a new file is created, like file4.txt, before completion of the loop?
How does for /R behave in that context? Supposed there are several sub-directories sub1, sub2, sub3, each containing the above list of files; for /R is currently iterating through sub2, sub1 has already been processed, but sub3 not yet; the contents of sub1 and sub3 are changed at that point (when currently walking through sub2 as mentioned); what will be enumerated then? I guess, the change of the content of sub1 won't be recognised, but what about sub3?
Finally, is there a difference in behaviour of for or for /R when being executed in the command prompt or from a batch file? And are there differences in different Windows versions?
Note:
See also my similar question about the forfiles command.
This is an excellent question!
Let's concentrate on plain for command for a moment. There is a known bug related to this command when it is used to rename files. For example:
set i=0
for %%a in (*.txt) do (
set /A i+=1
ren "%%a" !i!.txt
)
In this case is frequently that certain files be renamed twice, and even three times in certain cases. The problem is that this behavior depends on a series of factors that are not documented, like the position of the first renamed file inside the list of original files and several other points. Similarly, if a file is deleted before it is processed by the for, a "File not found" message is usually issued (although not ALL times). If a new file is created in the directory after the for started execution, then it may or may not be processed by the for depending (again) on a series of factors. The usual way to avoid the problem with rename is to force for command to first read the whole list of files and then process the list:
for /F "delims=" %%a in ('dir /B *.txt') do (
set /A i+=1
ren "%%a" !i!.txt
)
This way, don't matters the changes that can be made on the files in the disk: the for /F command will always process the original file list.
A similar problem happen with for /R command, but in this case the possibility of problems is greater because there are more directories where dynamic changes can be made. Again: the exact behavior depends on a series of unknown factors and the way to avoid them is via for /F ... in ('dir /S /B'). However, if you are really interested in this point, I encourage you to made a series of tests on the subject (and post the results). ;)

how to move newest file in directory and then process the rest of the script

so i'm trying to take one file at a time out of a directory that contains 2000 files and going up and move it to a different directory to be worked on by the rest of my script. the script is below. Right now i know the gswin64 line works when it is alone and i specify it a filename but not i'm sure with the variable yet. But when i run this it will copy all the files in directory input to directory working before it runs the rest of the script. How do i make it do one at a time then process the script before copying the rest of the files?
for /F "delims=" %%I in ('dir "H:\documents\gs\input\*.*" /A-d /B /O:-D') do (move "H:\documents\gs\input\%%I" "H:\documents\gs\working"&goto filemoved)
:filemoved
Your original code would attempt to execute move "H:\documents\gs\input\*.*" "H:\documents\gs\working" which is why all of th files were moved. What you need to do is execute a directory list command with the switch parameters and supply that to the for /f. This form of dir will show names only. so you need to include the source directory name in the move command. You would also need to have the "delims=" option to ensure that filenames containing separators are processed correctly, and the /a-d directory switch to ensure that directory names are not included. Since you are sorting in reverse-date order, the newest file will be selected first. After the first file is moved, you need to abort the for loop otherwise it will continue processing the entire list, transferring every file. The easy way here is to simply goto a label on the next line.
You've also used a *.* filemask, which will process all files, regardless of extension. Since you appear to want to process only .pdf files, you should probably change that filemask to suit.
for /F "delims=" %%x in ('dir H:\documents\gs\working\*.pdf /b') do set "FileName=%%x"
Again, you need to execute a dir command if you are using a for /f. There's no apparent reason why you wouldn't use the far simpler
for %%x in (H:\documents\gs\working\*.pdf) do set "FileName=%%x"
In either case, you probably want only the name part of the file, so FileName should be set to %%~nx, not %%x.
"C:\program files\gs\gs9.20\bin\gswin64" -o H:\documents\gs\output\"%FileName%" -sDevice=pdfwrite -dFitPage -dFIXEDMEDIA H:\documents\gs\working\"%FileName%"
Unbalanced quotes - the full pathname to the executable needs to be quoted since it contains a separator. Stray spaces after \ will probably need to be removed.
It would be better imho to quote the entire filename, including drive and path rather than filename only.
del /q H:\documents\gs\working\*.*
rm is not a batch command. Note that this command will delete ALL files in H:\documents\gs\working - not just the .pdf files that you appear to be processing.
goto start
The space is required. gotostart is not an inbuilt command.

batch Moving all files in 100s of folders up one folder

I have a small issue. I'm not super fluent in batch scripting but i'm trying to get better.
I'm trying to get a script working at my current job that we can use to move all files in the last sub-directory of a parent up one directory.
The need is for moving image sequences delivered with a superfluous sub-directory up one sub-directory for effects workflow
essentially i'm being delivered 100s of image sequences as:
Episode/Footage/shot/resolution/shot.0000001.dpx
I would love a batch script i could move into the "Footage" folder that would parse the shot directories below them and move the image sequences out of the resolution folder and place them directly into the shot folder so the structure would look more like this:
Episode/Footage/shot/shot.0000001.dpx
This batch would need to be reused over many instances and just be robust enough to be reusable regardless of what the extensions on the image sequences are or the naming structure of the subfolders are.
for /f "delims==" %%i in ('dir /a:d /b') do for /f "delims==" %%f in ('dir "%%i" /a:d /b') do (move "%%i\%%f\*" "%%i"&&rd "%%i\%%f" /s /q)
The * can be replaced with * . * (no spaces) to only grab files.
Use % instead of %% for use on the command line.
This will grab from any dir under Footage. Delete the first for loop and replace all occuences of %%i with shot to only grab from there.
#!/bin/bash
mv Episode/Footage/Shot/*/* Episode/Footage/Shot
Or for more Fanciness:
#!/bin/bash
echo "Write the file path:"
read file_path
mv $file_path/*/* $file_path/
This will ask you what the path is (This is Episodes/Footage/shot in your example) then find all the files in that path and all the files inside them and put them all in the path.
You could also modify this if instead of putting the files in the path you want them in a different place you could add:
echo "Write the destination file path:"
read file_path2
in between: read file_path and mv ...
and change:
mv $file_path/*/* $file_path
to:
mv $file_path/*/* $file_path2
There is really no need to go through so much trouble.
With the exceptions of the PUSHD and POPD commands, the whole thing can be placed on one line like nephi12 did.
I'm puting everything on separate lines for clairity's sake, but will give two examples of it on one line later.
REM Set working directory
PUSHD C:\Episode\Footage\
REM Find all the sub directories of the working
REM directory, and if any exist execute the loop below:
For /d %%d in ( *.* ) do (
REM Move all files inside the subdirectory up one level.
move /s %%d\*.* %%d\..\.
REM Delete the directories if they are empty.
RD /y %%d
)
REM Return to your original working directory.
POPD
The above code pushes the current directory name into a stack, and changes dirs to Footage.
Then the For /d command grabs all (if any) of the sub directories of Footage, and feeds them one at a time first into the MOVE command, then into the Remove Directory command.
The MOVE /s command moves all files in directory %%d (including any in sub folders) up one level.
Next the RD /y command automatically deletes the now empty directories, or causes a soft error if they are not empty.
The final command returns the working directory to it's original location, POPing the path off the stack.
On one line, without the PUSHD and POPD commands and the directory cleanup, it looks like this:
Single Line Solution:
For /d %%d in ( *.* ) do move /s %%d\*.* %%d\..\.
Single Line Solution with Cleanup:
To include the cleanup just 'add' the and command && after the move command and before the RD, like so:
For /d %%d in ( *.* ) do ( move /s %%d\*.* %%d\..\. & RD /y %%d )
Why I did what I did.
The fastest way to move a whole bunch of files, is not to tell move how and where to move each file, but to use wild cards that will allow Move to figure out by it'self where to put them. So rather than tell it to move one file at a time, I give it wild cards, which allowsMOVE to work at it's fastest. So I only feed it the individual source and destination directories, and say "copy ALL files from here to there".
A set of brackets (...) can hold, what the interpreter considers a single line of code. Which causes a whole new set of problems, but it allows a special variable like %%d to exist on (what to us appears to be) multiple lines of code. I did that at the top. Later, I used another set of brackets to show the command interpreter what is part of a single line is inside a FOR statement, and what is not.
I also used a bit of old DOS shorthand to specify a parent directory, .. which allows me to not know the exact path of something, and still manipulate things in it's parent . As an example,C:\WINDOWS\.. is C:\, and C:\WINDOWS\SYSTEM32\.. is C:\WINDOWS\ .
You might notice that I also used the file specification . . That is probably unnecessary, but I've ran into enough trouble without it that I use it. It just makes clear to MOVE that we are moving these files to a folder, not a file. And, oh yes, MOVE will gladly move hundreds of your files on top of each other, ruining them all but the last one. You can imagine how I came to embrace the . .
The & allows you to string multiple commands, or programs, onto a single line of code, and allows me to tack the RD to the end of the line, and still have access to the special variables that the FOR command created.
So, now if you were paying attention, you'd have realized that my second sentence was a fib. There is nothing stopping you from tacking a PUSHD & and a & POPD onto the beginning and end of that line.

DOS- keeping portion of directory structure during xcopy?

I am a bit new to DOS batch files, and I am having a hard time wrapping my head around ways to solve my problem.
What I need to do: I have a large, nested source folder structure, let's say it lives here:
C:\dir1\dir2\dir3\file.txt
And I have a mirrored destination structure, although a portion of the root is different:
x:\dirA\dirB\dir1\dir2\dir3\file.txt
My current batch copies all files in the source structure to a destination folder, keeping the folder structure, which is what I want.
The problem:
The intention of my script is to drag a folder from the source structure above onto the bat file, and have it copy the files to the destination. What I want to do, is to allow the user to drag a folder from source dir, let's say /dir2 and all of its subfolders/files onto the batch file, and have it copy the contents over to the SAME spot in the destination structure...
So in this example, the batch file should copy everything in and below:
C:\dir1\dir2\
into
x:\dirA\dirB\dir1\dir2\.
Fortunately (I think) my destination folder structure won't be changing, although the source might be in a different location on each machine. So, if there is a clever way to detect where in the source tree I am, and then replace a portion of the destination path... ???
Here's my simple script so far:
#echo off
set /p FILETYPE="What file type do you want to copy? (For example use txt, max, f3d, or * to copy all files.)"
xcopy %1\*.%FILETYPE% c:\output /s
pause
Thanks so much for any help you guys can give! :)
Ken
UPDATE: Adding updated code sample here because I cannot get my comment to format or allow me enough chars. The stuff below may not be completely correct, I am just trying my best to be clear. I have figured out more since I posted this, basically I need to figur out how (or if possible) to use a string after delims, it only seems to check for each character...
#echo off
rem user drag folder onto .bat (left click, move folder using mouse onto .bat icon)
rem %1 in ex is C:\random_folder\another_folder\proj1\area1\scene23
set destRoot=X:\companyname\allprojects\proj1
set rootDir=proj1
rem assume %1 is folder dragged onto .bat file
for /f "tokens=2* delims=<foldername???>" %%a in ("%1") do (
set part1=%%a
set chunk=%%b
)
set finalDest=destRoot+chunk
xcopy %1\* %finalDest% /E /EXCLUDE:exclusions.txt
pause
I am hoping to create this: "X:\companyname\allprojects\proj1\area1\scene23"
Is the x:\dirA\dirB\ part of the destination folder known? If so, the solution is easy:
#echo off
rem Get current directory, ie: "C:\dir1\dir2"
set curDir=%cd%
rem Eliminate the disk drive, ie: "\dir1\dir2"
set curDir=%curDir:~2%
rem Copy to right destination, ie: "x:\dirA\dirB\dir1\dir2"
xcopy *.%FILETYPE% "x:\dirA\dirB%curDir%"
I hope it helps...
EDIT: Clarification to new comments requested
Ok. There is a source folder and a destination folder. The program above assume that the current folder for the program is source folder, but this may be provided as a parameter if needed. The program achieve the following copy processes:
From source folder -> To destination folder
C:\dir1\dir2 -> x:\dirA\dirB\dir1\dir2
C:\dir1\dir2\dir3 -> x:\dirA\dirB\dir1\dir2\dir3
C:\dir1\dir2\dir3\what\ever -> x:\dirA\dirB\dir1\dir2\dir3\what\ever
C:\XYZ -> x:\dirA\dirB\XYZ
If this is not what you want then explain it as concise as possible (use "files", "folder", "part of name" terms, not "I like", "what if", etc), and include three or four examples.
Also, note that for me drag a folder mean a drag&drop operation taking the source folder pressing the right button of the mouse and leave it over the icon of the Batch file. If you are NOT refering to this operation, please do NOT use "drag" term; use "copy" instead (please also clarify this point).
EDIT: Solution to new requirements
OK! You have not explained correctly before your last example! This problem is just about matching two names: last part of first name must match the same part in second name, and combine first name and the rest of second name. Right?:
First name: X:\companyname\allprojects\proj1
Second name: C:\random_folder\another_folder\proj1\area1\scene23
Result: X:\companyname\allprojects\proj1\area1\scene23
This is the solution:
#echo off
setlocal EnableDelayedExpansion
rem user drag folder onto .bat (left click, move folder using mouse onto .bat icon)
rem %1 in ex is C:\random_folder\another_folder\proj1\area1\scene23
set sourceFolder=%~1
set destRoot=X:\companyname\allprojects\proj1
rem Get last part of First name (destRoot) ie: lastPart=proj1
for %%a in (%destRoot%) do set lastPart=%%~Na
rem Delete from beginning of second name until that part, ie: result=\area1\scene23
set result=!sourceFolder:*%lastPart%=!
rem And insert the First name before the rest
set result=%destRoot%%result%
Or, combining the three steps in just one line:
#echo off
rem user drag folder onto .bat (left click, move folder using mouse onto .bat icon)
rem %1 in ex is C:\random_folder\another_folder\proj1\area1\scene23
set sourceFolder=%~1
set destRoot=X:\companyname\allprojects\proj1
for %%a in (%destRoot%) do set result=%destRoot%%sourceFolder:*%%~Na=%
Please note that if destRoot may contain spaces, it must be enclosed in quotes in the FOR command: for %%a in ("%destRoot%") do ...
Got this on another forum, seems to contain the answr I was looking for, sharing here for others:
#echo off
REM YOU NEED THIS
setlocal enabledelayedexpansion
REM If the passed parameter string has any spaces you must quote it
REM we unquote it using ~
set PassedString=%~1
REM May as well do the same with string to split on
set DelimString=%~2
REM The delim string must appear exactly ONCE in the passed string
REM Replace the delim string with a symbol which will not be in the
REM path to be split, in this example I use #
set splitsub=#
call set tempstring=!PassedString:%DelimString%=%splitsub%!
REM Use FOR to split the modified string
for /f "tokens=1* delims=%splitsub%" %%A in ("%tempstring%") do set part1=%%A & set part2=%%B
REM Show that the 2 variables contain the desired substrings
echo Passed = %PassedString%
echo Part1 = %part1%
echo Part2 = %part2%
Example output:
C:\>splitstring.bat "D:\Backup\mystuff\programming\Visual Basic\project\ABCDE\DEF" "project"
Passed = D:\Backup\mystuff\programming\Visual Basic\project\ABCDE\DEF
Part1 = D:\Backup\mystuff\programming\Visual Basic\
Part2 = \ABCDE\DEF
C:\>splitstring.bat "D:\Backup\mystuff\programming\Visual Basic\project\ABCDE\DEF" "mystuff"
Passed = D:\Backup\mystuff\programming\Visual Basic\project\ABCDE\DEF
Part1 = D:\Backup\
Part2 = \programming\Visual Basic\project\ABCDE\DEF

Resources