Batch file for loop statement - windows

I've put together the batch file below; I don't have much experience with batch files and I can't figure out why the file fails with an error message stating that the:
DO command was unexpected.
Looking at the following code, does anyone know what I did wrong? Thanks.
#ECHO OFF
REM Set arguments supplied by Subversion
SET REPOS = %1
SET REV = %2
REM Set working directory path
SET WORKSPACE = D:\apache\htdocs
REM Assign changes to variable
SET CHANGES = svnlook changed %REPOS% -r %REV%
REM Update only changed files
FOR /f %%a IN %CHANGES% DO svn update %%a

FOR /f %%a IN %CHANGES% DO svn update %%a
should be
FOR /f %%a IN (%CHANGES%) DO svn update %%a
Hope this helps,

I'm guessing that %CHANGES% is not in the correct format/structure for the loop so the DO cannot be executed. Add the following line before the loop to check you're getting what you expected from the SET CHANGES command;
ECHO %CHANGES%
If the assignment is more batch code to execute you might need to use CALL. What are you passing in when calling the batch file for %1 and %2?

can you try to run it without the REM Statement. Comments sometimes make things work differently.

After modifying my original code I've got it to 'work.'
The svnlook command returns for example: trunk\images\smileyface.jpg
Currently, the for loop returns only the 'U' rather than the 'smileyface.jpg' which I want. So, while the code now works, it does function yet how I'd like (still working on it).
Below is the revamped code (Note: I had to remove all spaces between my variables and their assigned values).
#ECHO OFF
REM Set arguments supplied by Subversion
SET REPOS=%1
SET REV=%2
REM Set working directory path
SET WORKSPACE=D:\apache\htdocs
REM Assign changes to variable
SET CHANGES=svnlook changed %REPOS% -r %REV%
REM Update only changed files
FOR /F "usebackq" %%a IN (`%CHANGES%`) DO (svn update %%a)

Related

How to get a specific line from command output in batch script into a variable?

I'd like to get a changelist description from perforce, which involves calling a p4 describe -s , so the ouput would be as below. Is there a way to get (trimmed characters from the third line) from the output just using windows batch syntax?
Change 6582 by username on 2016/12/06 00:35:41
MyChangeDescription
Affected files ...
... //depot/foo.txt#7 edit
... //depot/foo2.txt#6 edit
Give this a shot:
p4 -Ztag -F %Description% change -o 6582
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q40986156.txt"
FOR /f "usebackqskip=2tokens=*" %%a IN ("%filename1%") DO (
SET "desc=%%a"
GOTO show
)
:show
ECHO "%desc%"
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q40986156.txt containing your data for my testing.
This uses a file as input. Since I don't have access to perforce, I can't test it but
#ECHO OFF
SETLOCAL
FOR /f "skip=2tokens=*" %%a IN ('p4 describe -s') DO (
SET "desc=%%a"
GOTO show
)
:show
ECHO "%desc%"
GOTO :EOF
should be equivalent.
Simply, read the output of the command, skip the first 2 lines, tokenise the entire line, skipping leading spaces. Assign the string found to a variable and immediately exit the loop.

String replacement within FOR /F into batch file

There are a handful of questions on SO that look similar, but I cannot figure out some behaviour and I am looking for help.
Below is a snippet from a batch file I am trying to write which will load in a set of directories and potentially replace letter substitutions with an expanded path, e.g. the properties file might look like:
location1=C:\Test
location2=[m]\Test
Where location1 points to C:\Test and location2 points to C:\Program Files(x86)\MODULE\Test, because [m] is a shorthand to C:\Program Files(x86)\MODULE.
The batch script, to this point, is simply trying to read in the list of file paths and expand/replace the [m].
SET build.dir=%~dp0%
SET progfiles=%PROGRAMFILES(X86)%
IF "%progfiles%"=="" SET progfiles=%ProgramFiles%
SET local.properties=%build.dir%local.properties
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "tokens=1* delims==" %%i IN (%local.properties%) DO (
SET local.dir=%%j
SET local.dir=!local.dir:[m]=%progfiles%\MODULE!
echo !local.dir!
)
ENDLOCAL
Running this kicks out an error:
\MODULE was unexpected at this time.
If I replace the FOR with the following instead:
set test="[m]\Proj\Dir"
set test=!test:[m]=%progfiles%\MODULE!
echo %test%
I get the desired C:\Program Files(x86)\MODULE\Proj\Dir printed out...so I'm confused why it works fine outside of the FOR loop.
My understanding about delayed expansion is that it 'expands' at runtime...which you get to happen using !! instead of %% wrapped around the variable. Furthermore, as I'm creating the local.dir variable inside the FOR loop scope, I must use delayed expansion in order to access it with the updated value for the iteration.
I feel like the problem is using %progfiles%, like there's some special syntax I need to use in order to make it work but nothing is adding up for me. When I echo %progfiles%, it prints out as C:\Program Files(x86 -- note the missing trailing ).
Any ideas? Thanks
Tested suggestion:
D:\Projects\Test\Build>test
*** "D:\Projects\Test\Build\local.properties"
*** "","C:\Program Files (x86)"
[m]=C:\Program Files (x86)\MODULE
Adding quotes around the whole expression makes it work -- can't use other characters for some reason (like []) -- and since I want to append to the path later, we can safely remove the quotes afterwards:
SET local.dir="!local.dir:[m]=%progfiles%\MODULE!"
SET local.dir=!local.dir:"=!
Test this to see if you can nut out the issue:
The double quotes are to provide robust handling in a system with long file/path names.
The () are unquoted which are a problem in a batch script, when inside a loop.
#echo off
SET "build.dir=%~dp0%"
SET "progfiles=%PROGRAMFILES(X86)%"
IF "%progfiles%"=="" "SET progfiles=%ProgramFiles%"
SET "local.properties=%build.dir%local.properties"
echo *** "%local.properties%"
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "usebackq tokens=1* delims==" %%i IN ("%local.properties%") DO (
SET "local.dir=%%j"
echo *** "!local.dir!","%progfiles%"
SET "local.dir=!local.dir:[m]=%progfiles%\MODULE!"
echo !local.dir!
)
ENDLOCAL
pause
It has to do with the () characters that end up in your progfiles string. If you take them out, the substitution seems to work fine.
My suggestion is to ditch command for this particular purpose and use one of the other standard tools that Windows comes with. While my personal preference would be Powershell (since it's so much more powerful and expressive), you may just need something quick that you can integrate into existing cmd.exe stuff.
In that case, try the following VBScript file, xlat.vbs:
set arg = wscript.arguments
wscript.echo Replace(arg(0),arg(1),arg(2))
Your batch file then becomes something like, noting the inner for /f which captures the output of the VBS script and assigns it to the variable:
#echo off
SET build.dir=%~dp0%
set progfiles=%PROGRAMFILES(X86)%
if "%progfiles%"=="" set progfiles=%ProgramFiles%
set local.properties=%build.dir%local.properties
setlocal enabledelayedexpansion
for /f "tokens=1* delims==" %%i in (%local.properties%) do (
set local.dir=%%j
for /f "delims=" %%x in ('cscript.exe //nologo xlat.vbs "!local.dir!" "[m]" "%progfiles%\MODULE"') do set local.dir=%%x
echo !local.dir!
)
endlocal
Running that, I get the output:
C:\Test
C:\Program Files (x86)\MODULE\Test
which I think is what you were after.

Remove unwanted path name from %path% variable via batch

Scope: Windows XP or newer
Tools: Batch script
I need to be able to remove an unneeded path name from the system %PATH% variable. I know how to add a new path name to the system %PATH% variable, using a tool such as SETX.EXE, which also makes it immediately available within the existing CMD environment. It's probably a matter of using FIND and/or a FOR loop of some kind, but I'm not quite sure how to accomplish this. Here's a sample path statement...
%PATH% = C:\;C:\Program Files\Common Files\Java;C:\oracle\product\10.2.0\bin;C:\WINDOWS;C:\WINDOWS\system32;
From this, I need to be able to remove the full path name related to "oracle." So, in the above example, I need to be able to remove the "C:\oracle\product\10.2.0\bin" from the above path statement. Unfortunately, not only could the oracle path name be different than shown above, there could be multiple oracle path names and all need to be removed. I tried implementing the solution here...
How can I extract a full path from the PATH environment variable?
However, it just isn't working. The script wouldn't find the path name. Any help would be appreciated. Thank you.
This removes the substring C:\Program Files (x86)\Git\bin; from the PATH string and re-assigns:
set PATH=%PATH:C:\Program Files (x86)\Git\bin;=%
You might use this to see the change:
echo %PATH:C:\Program Files (x86)\Git\bin;=% | tr ; \n
Note: be exact on the substring. It's case-sensitive and slash-sensitive.
If you need to make it a persistent change use setx instead of set and open another console for changes to take effect.
setx /M PATH "%PATH:C:\Program Files (x86)\Git\bin;=%"
You can try something like this :
#echo off&cls
setlocal EnableDelayedExpansion
set $line=%path%
set $line=%$line: =#%
set $line=%$line:;= %
for %%a in (%$line%) do echo %%a | find /i "oracle" || set $newpath=!$newpath!;%%a
set $newpath=!$newpath:#= !
echo set path=!$newpath:~1!
I putted an echo to the last line. Check the result and If it's OK for you, remove it.
After trying SachaDee's answers I got errors with paths like
C:\Program Files (x86)
with brackets:
Program Files (x86)\Directory
gave me
Directorywas unexpected at this time. (no matter what time I tried it)
I added
set $line=%$line:)=^^)%
before the for-loop and
set $newpath=!$newpath:^^=!
after the loop (not sure if it is necessary)
#echo off
setlocal EnableDelayedExpansion
set path
set $line=%path%
set $line=%$line: =#%
set $line=%$line:;= %
set $line=%$line:)=^^)%
for %%a in (%$line%) do echo %%a | find /i "oracle" || set $newpath=!$newpath!;%%a
set $newpath=!$newpath:#= !
set $newpath=!$newpath:^^=!
set path=!$newpath:~1!
And it is now working.
I found the other solutions to this problem a bit awkward, I don't really want to rely on exact paths, complex 'delayed expansion' syntax, removing spaces for the 'for /f' loop and then adding them back in...
I think this is more elegant, and I commented the hell out of it so even someone new to the horrors of Batch can follow along.
::Turn off command display and allows environmental variables to be overridden for the current session
#echo off & setlocal
::Creates a unique file to use for the 'for loop'
set "TMPFILE="%temp%\tmp%RANDOM%%RANDOM%.txt""
::Duplicate PATH into OLDPATH
set "OLDPATH=%PATH%"
::Declare label for the 'goto' command
:Loop
::Extract the first text token with the default delimiter of semicolon
for /f "tokens=1 delims=;" %%G in ("%OLDPATH%") do (
REM Copy text token to TMPFILE unless what we want to remove is found
<NUL set /p="%%G" | find /i "StRiNgThAtMaTcHeSwHaTtOrEmOvE" >NUL 2>&1 || <NUL set /p="%%G;" >>%TMPFILE%
REM Remove text token from OLDPATH
set "OLDPATH=%OLDPATH:*;=%"
)
::Repeat loop until OLDPATH no longer has any delimiters, and then add any remaining value to TMPFILE
echo %OLDPATH% | findstr /C:";" >NUL && (goto :Loop) || <NUL set /p="%OLDPATH%" >>%TMPFILE%
::Set the path to TMPFILE
for /f "usebackq delims=" %%G in (%TMPFILE%) do (set "PATH=%%G")
::Clean-up
del %TMPFILE% >NUL 2>&1
::An echo and pause just for debug purposes
echo %PATH%
pause
I use this in CYGWIN to filter out CYGWIN paths before starting some Windows commands:
export PATH=`perl -e '#a=grep {$_ =~ /^\/cygdrive\//} split(":", $ENV{PATH});print join(":",#a)'`
I'm quite sure it's easy to adapt to Windows-native perl and bat files. Advantage: the flexible power of regular expressions.
I wanted to remove %LocalAppData%\Microsoft\WindowsApps; from PATH. But this was not possible due to using a another variable in the environment variable for Windows. The CALL hack is worked in SS64. (Also, thanks to Jens A. Koch for the base command.)
CALL set PATH=%PATH:%LocalAppData%\Microsoft\WindowsApps;=%
Of course, the PATH changing by SET will not be permanent. For fixed change, it is necessary to use the SETX command or directly change the entries in the Registry.
Actually, this solution was not needed to delete %LocalAppData%\Microsoft\WindowsApps; from PATH.
The %LocalAppData%\Microsoft\WindowsApps; is stored in the PATH entry of the Registry's HKCU\Environment key. Although it is more practical to delete this entry with the REG DELETE command, if there are another directories in the PATH entry, they will also be deleted, so new solution is needed.
I failed to remove the %USERPROFILE% variable syntax from SET (The %% symbol dilemma). Fortunately, PShell came to the rescue:
SET userprofile=
Powershell -c "$UserEnvironmentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User'); $UserEnvironmentPath = $UserEnvironmentPath.Replace('%USERPROFILE%\AppData\Local\Microsoft\WindowsApps;',''); [Microsoft.Win32.Registry]::SetValue('HKEY_CURRENT_USER\Environment', 'Path', $UserEnvironmentPath, [Microsoft.Win32.RegistryValueKind]::ExpandString)"
Special thanks to vonpryz for the last command. Because PowerShell's [System.Environment]::SetEnvironmentVariable command saves variables to Registry as REG_SZ even if their original value type is REG_EXPAND_SZ, which it's the known issue.
I wrote this code to simply remove any python executeable path from the path variable,
and insert my own specefic python version in the path so i can run python with
the versoin i wanted.
setlocal enableDelayedExpansion
set path`enter code here`
set $line=%path%
set $line=%$line: =#%
set $line=%$line:;= %
set $line=%$line:)=^^)%
set newpath=
for %%a in (%$line%) do (
echo %%a | find /i "python" ||set newpath=!newpath!;%%a
)
set path=!newpath!
set PATH=D:\python2.7\;%PATH%
#REM Rest of your script
python --version
#REM to exit the batch but not the window
exit /b
also, the first line is important! don't remove it or it wont work.
Notice: this code must run from a batch ".bat" file , if u want to copy paste this code in cmd window, you must replace all "%%a" to "%a" in this code.
If you know a file that exists within the directory you want to remove (e.g. want to remove all paths that might include java.exe), the following will work very straightforwardly by simply doing string replacement, no need to parse the path, etc:
#REM Executable to look for
set CMD=java.exe
:search
#REM Find the executable anywhere in the path
for %%a in (%CMD%) do set FOUND=%%~$PATH:a
if "%FOUND%"=="" goto done
#REM Strip \cmd.ext so we just have the directory
set FOUND=!FOUND:\%CMD%=!
#echo Found %CMD% in %FOUND%
#echo Removing %FOUND% from path...
set "PATH=!PATH:%FOUND%=!"
#REM Clean up any lone leftover \ in the path (in case the path was C:\foo\ instead of C:\foo)
set PATH=%PATH:;\;=;%
goto search
:done

Batch-script for determining relative paths in a loop

I want to implement a batch script in Windows 7 that iterates over all files in a folder and it cuts the folder prefix, e.g. Folder = "C:\A\B\" and the file = "C:\A\B\C\D.E" should output "C\D.E". My current code looks like this:
setlocal ENABLEDELAYEDEXPANSION
SET DIRECTORY=C:\DEV\SVN\QA\
for /R %DIRECTORY% %%f in (*.*) do (
REM GET RELATIVE PATH
echo File=%%f
echo Path=%TARGET_PATH_FOR_SOURCE%
set result=%f:!TARGET_PATH_FOR_SOURCE!=%
echo Result=!result!
)
I get the following result:
File=C:\DEV\SVN\QA\1.0\A\B\C.txt
Path=C:\DEV\SVN\QA\1.0
Result=C:\DEV\SVN\QA\1.0= <<< Expected result: "A\B\C.txt"
I found this here and tried this in the loop without success. Can you help me please?
Thank you!
This should work.
It's necessary to copy the FOR loop parameter to a variable, as the replace operations works only with variables.
#echo off
setlocal EnableDelayedExpansion
SET DIRECTORY==C:\DEV\SVN\QA
set TARGET_PATH_FOR_SOURCE==C:\DEV\SVN\QA\1.0
echo Path=%TARGET_PATH_FOR_SOURCE%
for /R %DIRECTORY% %%x in (*.*) do (
REM GET RELATIVE PATH
set "file=%%x"
set result=!file:%TARGET_PATH_FOR_SOURCE%=!
echo Result=!result!
)
referring to answer of "jeb":
i had a headache for hours getting this to work. obviously it was easier than expected. this:
SET DIRECTORY==C:\DEV\SVN\QA
set TARGET_PATH_FOR_SOURCE==C:\DEV\SVN\QA\1.0
must be written without "==":
set DIRECTORY=C:\DEV\SVN\QA
set TARGET_PATH_FOR_SOURCE=C:\DEV\SVN\QA\1.0
EDIT:
Well, It turns out that I had to do even more. Additionally change this:
set result=!file:%TARGET_PATH_FOR_SOURCE%=!
to this, then it should be fine:
call set result=%%file:!TARGET_PATH_FOR_SOURCE!=%%

Loop over folder string and parse out last folder name

I need to grab the folder name of a currently executing batch file. I have been trying to loop over the current directory using the following syntax (which is wrong at present):
set mydir = %~p0
for /F "delims=\" %i IN (%mydir%) DO #echo %i
Couple of issues in that I cannot seem to pass the 'mydir' variable value in as the search string. It only seems to work if I pass in commands; I have the syntax wrong and cannot work out why.
My thinking was to loop over the folder string with a '\' delimiter but this is causing problems too. If I set a variable on each loop then the last value set will be the current folder name. For example, given the following path:
C:\Folder1\Folder2\Folder3\Archive.bat
I would expect to parse out the value 'Folder3'.
I need to parse that value out as its name will be part of another folder I am going to create further down in the batch file.
Many thanks if anyone can help. I may be barking up the wrong tree completely so any other approaches would be greatly received also.
After struggling with some of these suggestions, I found an successfully used the following 1 liner (in windows 2008)
for %%a in (!FullPath!) do set LastFolder=%%~nxa
You were pretty close to it :) This should work:
#echo OFF
set mydir="%~p0"
SET mydir=%mydir:\=;%
for /F "tokens=* delims=;" %%i IN (%mydir%) DO call :LAST_FOLDER %%i
goto :EOF
:LAST_FOLDER
if "%1"=="" (
#echo %LAST%
goto :EOF
)
set LAST=%1
SHIFT
goto :LAST_FOLDER
For some reason the for command doesn't like '\' as a delimiter, so I converted all '\' to ';' first (SET mydir=%mydir:\=;%)
I found this old thread when I was looking to find the last segment of the current directory.
The previous writers answers lead me to the following:
FOR /D %%I IN ("%CD%") DO SET _LAST_SEGMENT_=%%~nxI
ECHO Last segment = "%_LAST_SEGMENT_%"
As previous have explained, don't forget to put quotes around any paths create with %_LAST_SEGMENT_% (just as I did with %CD% in my example).
Hope this helps someone...
This question's a little old, but I've looked for a solution more than once so here's a completely new take on it that I've just put together.
The trick is that we take the desired path, back up one level to create a folder mask for substitution and then replace the folder mask with nothing.
To test it, simple copy and paste into a command script (.cmd) in any directory, then run it. It will spit out only the deepest directory you're currently in.
Notes:
Replace %~dp0 with whatever path you like (as it is, it will return the deepest folder the batch file is run from. This is not the same as %cd%.)
When specifying the 'pathtofind' variable ensure there are no quotes e.g. c:\some path and not "c:\some path".
The original idea for folder masking is mine
Spaces in the path are no problem
Folder depth is not a problem
It was made possible by the genius of this batch scripting tip http://www.dostips.com/DtCodeBatchFiles.php#Batch.FindAndReplace
Hope this helps someone else.
#echo off
set pathtofind=%~dp0
if not exist %pathtofind% echo Path does not exist&pause>nul&goto :eof
cd /d %pathtofind%
set path1=%cd%
cd ..
set path2=%cd%
call set "path3=%%path1:%path2%\=%%"
echo %path3%
pause>nul
3 lines of script gets the result...
Found 2 additional ways to accomplish the goal, and unlike the other answers to this question, it requires no batch "functions", no delayed expansion, and also does not have the limitation that Tim Peel's answer has with directory deepness :
#echo off
SET CDIR=%~p0
SET CDIR=%CDIR:~1,-1%
SET CDIR=%CDIR:\=,%
SET CDIR=%CDIR: =#%
FOR %%a IN (%CDIR%) DO SET "CNAME=%%a"
ECHO Current directory path: %CDIR%
SET CNAME=%CNAME:#= %
ECHO Current directory name: %CNAME%
pause
REVISION: after my new revsion, here is an example output:
Current directory path: Documents#and#Settings,username,.sqldeveloper,tmp,my_folder,MY.again
Current directory name: MY.again
Press any key to continue . . .
This means that the script doesn't handle '#' or ',' in a folder name but can be adjusted to do so.
ADDENDUM: After asking someone in the dostips forum, found an even easier way to do it:
#echo off
SET "CDIR=%~dp0"
:: for loop requires removing trailing backslash from %~dp0 output
SET "CDIR=%CDIR:~0,-1%"
FOR %%i IN ("%CDIR%") DO SET "PARENTFOLDERNAME=%%~nxi"
ECHO Parent folder: %PARENTFOLDERNAME%
ECHO Full path: %~dp0
pause>nul
To return to the original poster's issue:
For example, given the following path:
C:\Folder1\Folder2\Folder3\Archive.bat
I would expect to parse out the value 'Folder3'.
The simple solution for that is:
for /D %%I in ("C:\Folder1\Folder2\Folder3\Archive.bat\..") do echo parentdir=%%~nxI
will give 'Folder3'. The file/path does not need to exist. Of course, .... for the parent's parent dir, or ...... for the one above that (and so on) work too.
Slight alteration for if any of the folders have spaces in their names - replace space to ':' before and after operation:
set mydir="%~p0"
set mydir=%mydir:\=;%
set mydir=%mydir: =:%
for /F "tokens=* delims=;" %%i IN (%mydir%) DO call :LAST_FOLDER %%i
goto :EOF
:LAST_FOLDER
if "%1"=="" (
set LAST=%LAST::= %
goto :EOF
)
set LAST=%1
SHIFT
goto :LAST_FOLDER
Sheesh guys, what a mess. This is pretty easy, and it's faster to do this in memory without CD.
This gets the last two directories of a path. Modify it as required to get the last tokens of any line. My original code I based this on has more complexity for my own purposes.
Fyi, this probably doesn't allow paths with exclamation marks since I'm using enabledelayedexpansion, but that could be fixed.
It also won't work on a plain drive root. This could be averted in a number of ways. Check what the input path ends with, or a counter, or modifying the token and check behaviour, etc.
#echo off&setlocal enableextensions,enabledelayedexpansion
call :l_truncpath "C:\Windows\temp"
----------
:l_truncpath
set "_pathtail=%~1"
:l_truncpathloop
for /f "delims=\ tokens=1*" %%x in ("!_pathtail!") do (
if "%%y"=="" (
set "_result=!_path!\!_pathtail!"
echo:!_result!
exit/b
)
set "_path=%%x"
set "_pathtail=%%y"
)
goto l_truncpathloop
I modified answer given by #Jonathan, since it did not work for me in a batch file, but this below does work, and also supports folders with spaces in it.:
for %%a in ("%CD%") do set LastFolder=%%~nxa
echo %LastFolder%
This takes the current directory and echoes the last, deepest folder, as in below example, if the folder is this:
C:\Users\SuperPDX\OneDrive\Desktop Environment\
The batch code echoes this: Desktop Environment
In batch files in the FOR command you'll need to prepend %whatever with an extra % (e.g. %%whatever).
'echo %~p0' will print the currently directory of the batch file.
This is what we had in the end (little bit more crude and can only go so deep :)
#echo off
for /f "tokens=1-10 delims=\" %%A in ('echo %~p0') do (
if NOT .%%A==. set new=%%A
if NOT .%%B==. set new=%%B
if NOT .%%C==. set new=%%C
if NOT .%%D==. set new=%%D
if NOT .%%E==. set new=%%E
if NOT .%%F==. set new=%%F
if NOT .%%G==. set new=%%G
if NOT .%%H==. set new=%%H
if NOT .%%I==. set new=%%I
if NOT .%%J==. set new=%%J
)
#echo %new%
I don't know if it's the version of windows I'm on (win2k3), but the FOR loop isn't giving me anything useful for trying to iterate through a single string.
According to my observation (and the FOR /? info) you get one iteration for each line of input to FOR, and there is no way to change this to iterate within a line. You can break into multiple tokens for a given line, but it is only one invocation of the FOR loop body.
I do think the CALL :LABEL approach in these answers does a great job. Something I didn't know until looking at this was that ";" and "," are both recognized as argument separators. So once you replace backslashes with semicolons, you can call your label and iterate through with SHIFT.
So working off of what is posted by others here, I have the below solution. Instead of grabbing the last folder name, I actually wanted to find everything up until some known directory name.. this is what is implemented below.
#echo off
if "%1"=="" goto :USAGE
set FULLPATH=%~f1
set STOPDIR=%2
set PATHROOT=
:: Replace backslashes with semicolons
set FULLPATH=%FULLPATH:\=;%
:: Iterate through path (the semicolons cause each dir name to be a new argument)
call :LOOP %FULLPATH%
goto :EOF
:LOOP
::Exit loop if reached the end of the path, or the stop dir
if "%1"=="" (goto :EOF)
if "%1"=="%STOPDIR%" (goto :EOF)
::If this is the first segment of the path, set value directly. Else append.
if not defined PATHROOT (set PATHROOT=%1) else (set PATHROOT=%PATHROOT%\%1)
::shift the arguments - the next path segment becomes %i
SHIFT
goto :LOOP
:USAGE
echo Usage:
echo %~0 ^<full path to parse^> ^<dir name to stop at^>
echo E.g. for a command:
echo %~0 c:\root1\child1\child2 child2
echo The value of c:\root1\child1 would be assigned to env variable PATHROOT
Unfortunatelly, this is working great only when put on some depth but have problems with being on the very top of the mountain... Putting this program into "C:\Windows" e.g. will result with... "C:\Windows", not expected "Windows". Still great job, and still damage can be repaired. My approach:
#echo off
set pathtofind=%~dp0
if not exist %pathtofind% echo Path does not exist&pause>nul&goto :eof
cd /d %pathtofind%
set path1=%cd%
cd ..
set path2=%cd%
set path4=%~dp1
call set "path3=%%path1:%path2%\=%%"
call set "path5=%%path3:%path4%*\=%%"
echo %path5%
pause>nul
And it's working just fine for me now, thanks for the idea, I was looking for something like that for some time.

Resources