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.)