28

I want to split the string (having a path) with \and take last folder name in a variable. Please help.

e.g
mypath=D:\FOLDER1\FOLDER2\FOLDER3\

I want FOLDER3 in a variable.

I tried with the command below which is working if the the last character is not \ :

for %f in (C:\FOLDER1\FOLDER2\FOLDER3) do set myfolder=%~nxf

It is not working if the last character is \

Also it is not working if variable is used like : for %f in (%mypath%) do set myfolder=%~nxf

Endoro
  • 37,015
  • 8
  • 50
  • 63
user2013
  • 283
  • 1
  • 3
  • 5

8 Answers8

36
@echo off

set MYDIR=C:\FOLDER1\FOLDER2\FOLDER3\
if "%MYDIR:~-1%" == "\" set "MYDIR1=%MYDIR:~0,-1%"

for %%f in ("%MYDIR1%") do set "myfolder=%%~nxf"
echo %myfolder%

outputs

FOLDER3
Gerhard
  • 22,678
  • 7
  • 27
  • 43
user93353
  • 13,733
  • 8
  • 60
  • 122
  • Thank you very much. This code is working as per my requirement. – user2013 Jun 24 '13 at 16:32
  • 10
    `%MYDIR:~0,-1%` appears to be some sort of substring method, but can someone explain what is happening in the for-loop ? – Walter Stabosz Dec 01 '14 at 21:04
  • 1
    It looks like it is becuase you didn't have a trailing slash at the end. If you append one, the above will work. – leeman24 Oct 06 '16 at 20:49
  • 2
    Alternatively you could take away the line `set MYDIR1=%MYDIR1:~0,-1%` which actually does delete the last character. To make it safe you can check if there is a trailing slash and if so delete the last char and if not let the string as it is :) – geisterfurz007 Nov 23 '16 at 07:06
  • 3
    When there are spaces in the path above method doesn't work. For example if the path is set MYDIR=C:\FOLDER1\FOLDER2\FOLDER 3\ it will return 3 instead of FOLDER 3 – Jan Jan 06 '17 at 11:48
  • 2
    Downvoted because none of the bugs in the comments was addressed. – user1944491 Sep 06 '20 at 17:52
  • @user1944491 Well done The answer was written 7 years back. – user93353 Sep 07 '20 at 01:11
  • @user93353 Time has no meaning on the Internet, as evidenced by the fact this question was relevant to me today, and the fact that you responded to my comment! :-) – user1944491 Sep 07 '20 at 13:41
  • 1
    @user1944491 why would I not respond. It was great to find someone looking at my answer after 7 years. TBH, most of the other comments were also much after the answer. When I wrote the answer, right after that there was only 1 comment - the first one. All other comments came much later - when I was probably on a break from here – user93353 Sep 07 '20 at 13:59
  • The 'substring method' trims off the trailing backslash. This converts from [the drive+path portion of a pathname] to [a validly-formatted pathname], complete with trailing filename[+ext]. The For-loop takes whatever is inside parentheses, and passes that as an argument to the Do-section, which executes on the argument. There is one string to iterate over, so Do runs once. The set command selects the filename+extension from the 'pathname' that was passed as %f. – Bilbo Mar 23 '21 at 05:46
21

try:

for %f in (C:\FOLDER1\FOLDER2\FOLDER3\.) do set myfolder=%~nxf

works also:

for %f in (C:\FOLDER1\FOLDER2\FOLDER3.) do set myfolder=%~nxf
Endoro
  • 37,015
  • 8
  • 50
  • 63
20

When your current folder contains spaces then try this:

@echo off
for %%f in ("%CD%") do set LastPartOfFolder=%%~nxf

echo %LastPartOfFolder%
Dirk
  • 233
  • 2
  • 6
1

The script below contains a subroutine that will handle paths with and without trailing slashes, and example tests of the same.

@echo off

::-----------------------------------------------------------------------------
:: Main script - testing the :get_last_folder subroutine.
::-----------------------------------------------------------------------------
setlocal enableExtensions

:: no trailing slash
call :get_last_folder C:\path\to\folder_0 _result
echo result: %_result%

:: one trailing slash
call :get_last_folder C:\path\to\folder_1\ _result
echo result: %_result%

:: extra slashes -- Windows doesn't care.
call :get_last_folder C:\path\to\folder_2\\ _you_can_use_any_variable_name
echo result: %_you_can_use_any_variable_name%

:: spaces in path
call :get_last_folder "C:\path\to\folder with spaces" _result
echo result: %_result%

:: no return variable -- Subroutine will ECHO the value.
call :get_last_folder C:\path\to\folder_to_echo

:: path of current directory
call :get_last_folder "%cd%" _result
echo result: %_result%

:: path of current directory after changing it
pushd "%userprofile%"
call :get_last_folder "%cd%" _result
echo result: %_result%

:: location of this file, independent of current directory
call :get_last_folder "%~dp0" _result
echo result: %_result%

:: restore previous current directory, cuz I'm not rude.
popd 

exit /b 

::-----------------------------------------------------------------------------
:: Subroutine
::-----------------------------------------------------------------------------
:get_last_folder <path> [return]
:: Extracts the last folder in a file system directory path.
:: Path may include zero, one, or more trailing slashes, but not a file name.

REM Use SETLOCAL to keep our subroutine variables from affecting the parent.
REM It also allows us to limit delayed variable expansion to where it's needed.
setlocal enableDelayedExpansion

REM Add a trailing slash to ensure the last element is seen as a folder.
REM If it already had a trailing slash, that's okay: extras are ignored.
set "_full_path=%~1\"

REM The caller can provide a variable name that we'll set to the return value.
REM If no return variable is given, we'll just ECHO the value before exiting.
set "_return=%~2"

for /f "delims=" %%F in ("%_full_path%") do (
    REM Treat the path as a string to avoid "file not found" error.
    REM Use loop variable expansion to get the "path" part of the path.
    REM The resulting string will always have exactly one trailing slash.
    set "_path=%%~pF"

    REM Use substring substitution to remove the trailing slash.
    REM Delayed expansion lets us access the new value while inside the loop.
    set "_path=!_path:~0,-1!"

    REM Without a trailing slash, the last element is now seen as a file.
    REM Use the "name" substring to get the value we came for.
    for /f "delims=" %%D in ("!_path!") do (
        set "_name=%%~nD"
    )
)

REM 
if defined _return (
    set "_command=set %_return%=%_name%"
) else (
    set "_command=echo\%_name%"
)

REM The "ENDLOCAL &" trick allows setting variables in the parent environment.
REM See https://ss64.com/nt/syntax-functions.html for more details.
endlocal & %_command%

goto :eof

I know it looks long, but that's just due to the test cases and lots of comments; the main subroutine code is about 10 lines, and some of that could go if you put it in it's own file.

Batch script subroutines are not true functions in the sense of being evaluated by an interpreter or compiler and then returning a value in place. Instead, they are a modified, fancy form of GOTO with support for local variables. Nonetheless, they are still useful for breaking up code into reusable portions and passing values around. While "pseudo-function" might be a better term, people often just say "function" anyway, so a search for "batch script functions" will give you useful results.

This is one of the oldest and best articles how batch "functions" work: https://www.dostips.com/DtTutoFunctions.php

This is a simpler, shorter explanation of functions, and is referenced inside the script: https://ss64.com/nt/syntax-functions.html

For an explanation on what the heck is going on inside FOR loops in CMD, see this writeup by the excellent Rob van der Woude: https://www.robvanderwoude.com/for.php

Sometimes reading isn't enough. Here's a great set of exercises to really get a grip on things: https://resources.infosecinstitute.com/cmd-exe-loops-part-iii/ (The CSS on this page went all screwy since the last time I looked at it, but you can copy the text out to a file and be fine.)

1

This works for me, not matter if path have spaces, special chars (& or similar) or \ at end (or not).

setlocal ENABLEDELAYEDEXPANSION

set "par=%~1"
:loop
for /f "delims=\ tokens=1,*" %%A in ("%par%") do (
    set "_last=%%A"
    set "par=%%B"
)
if NOT "%par%"=="" goto loop
echo Folder last name is :!_last!:
gonzalezea
  • 472
  • 3
  • 7
1

To put it in an easy subroutine that properly handles spaces:

@Echo Off

Rem Get name of folder containing this script.
Call :ParentFolderNamGet "%~dp0"

Rem Debug the variable.
Echo ParFldNam is [%ParFldNam%]

Pause

Rem Done with this script.
GoTo :EOF

Rem Argument to this subroutine must be a validly-formatted path (ends with a trailing backslash).
:ParentFolderNamGet

Rem Drop any enclosing double-quotes from caller's path, ensuring the last character is the path's trailing backslash.
Set Prm=%~1

Rem Drop trailing backslash; this converts the string from %~dp1 to %~dpn1 (the last folder name becomes a file name).
Set Prm=%Prm:~0,-1%

Rem Get only the 'filename' portion from the validly-formatted pathname.
For %%A In ("%Prm%") Do Set ParFldNam=%%~nxA

Rem Result is in %ParFldNam%
GoTo :EOF
Bilbo
  • 358
  • 1
  • 10
0

Great write-up guys. I like simple though...

rem set with or without spaces or trailing slash, but quotes are important...
set "_foldername=..."

rem cd command doesn't care if there's a trailing slash or not, and don't forget quotes...
cd "%_foldername%"   rem or pushd/popd if desired

rem as per @Dirk, use the %cd% system variable instead of the manually set variable,
rem this will return the current directory, always w/o a trailing slash.
rem again, as per @Dirk, quotes cause it to do spaces correctly.
for %%f in ("%cd%") do set _lastfolder=%%~nf

rem popd here, if used.

echo %_lastfolder%

Simple, right?

So... why is everyone using %nxf% (filename) instead of %nf% (folder)?

  • 1
    You don't even need `~n`, because `~f` contains `~dpnx`. But your soultion only works for existing paths. If you have a path to be created later or only want to check, it fails – jeb May 11 '21 at 05:36
  • 1
    `why is everyone using %nxf% (filename) instead of %nf% (folder)?` - because a folder name might contain a dot. (Btw: `%~nf` isn't `folder`, but `file (or folder) name without extension`) – Stephan May 11 '21 at 08:09
0

set MYDIR=C:\FOLDER1\FOLDER3
if "%MYDIR:~-1%" == "" set "MYDIR=%MYDIR:~0,-1%"

for %%f in ("%MYDIR%") do set "myfolder=%%~nxf" echo %myfolder%

OUTPUT - FOLDER3

this would work if MYDIR=C:\FOLDER1\FOLDER2\FOLDER3 (without trailing slash)

PS: I can't add comment for previous answer of user93353 - but this way would be more correct

VladimirK
  • 27
  • 6
  • I must miss something, but element would be "more correct"? Reusing `MYDIR` directly? – VonC Nov 21 '22 at 07:06