80} How can I extract the last part of a path such as C:\ABC\DEF\GHI\?
The core of question as posed on the Usenet news is how processing
>"C:\ABX\XYZ\" would return "XYZ"
>"C:\ABC\DEF\GHI" would return "GHI"
>"C:\ABC\DEF\GHI\" would return "GHI"
There are several solutions. First with
SED and
GAWK.
But before reading on, you may wish to revisit the previous
item #79
on trimming. Also see a later
item #115
on decomposing the path to be one folder per line.
@echo off & setlocal enableextensions
set mystr=C:\ABC\DEF XYZ\GHI\
echo %mystr%|sed -e "s/
\\*$//"
^
|gawk -F\ '{printf "@set last=%%s\n",$NF}'
^
>"%temp%\tmp$$$.cmd"
for %%c in (call del) do %%c "%temp%\tmp$$$.cmd"
echo %mystr%
echo %last%
endlocal & goto :EOF
The output will be
D:\TEST>cmdfaq
C:\ABC\DEF XYZ\GHI\
GHI
Observations on the above. The
sed -e "s/\\*$//"
sees to it that there are no trailing backslashes (\). The first
backslash
\, however, is an escape
character for sed which is needed to take the second \ literally. The
above also uses another escape character, the caret
^ to continue a CLI script command on the
next line.
Next let's take a step by step enhancements as often happens with
questions that have arisen when a discussion has continued on the
Usenet news about a particular problem.
Second solution, with pure script in a slow,
generic fashion.
@echo off & setlocal enableextensions enabledelayedexpansion
set mystr=C:\ABC\DEF XYZ\GHI\
echo %mystr%
:: Remove the last character
set mystr=%mystr:~0,-1%
echo %mystr%
:: Get the position of the last \
call :InstrLastFN "%mystr%" "\\" pos
set /a pos +=1
:: Get the desired substring
set result=!mystr:~%pos%!
rem echo %result%
for %%a in ("%mystr%") do echo %%~na
endlocal & goto :EOF
::
:: ============================================================
:InstrLastFN
setlocal enableextensions enabledelayedexpansion
echo %1|findstr %2>nul
if %errorlevel% EQU 1 (endlocal & set %3=-1& goto :EOF)
set rest_=%1
set /a instr_=-1
:_loop
set rest_=%rest_:~1%
echo !rest_!|findstr %2>nul
if %errorlevel% EQU 1 (endlocal & set %3=%instr_%& goto :EOF)
set /a instr_ +=1
goto _loop
endlocal & goto :EOF
The output will be
D:\TEST>cmdfaq
C:\ABC\DEF XYZ\GHI\
C:\ABC\DEF XYZ\GHI
GHI
The neatest solution is adapted from a posting by Phil Robyn.
@echo off & setlocal enableextensions disabledelayedexpansion
set mystr=C:\ABC\DEF XYZ\GHI\
echo %mystr%
set mystr=%mystr:~0,-1%
echo %mystr%
for %%a in ("%mystr%") do echo %%~na
endlocal & goto :EOF
Even that solution can be enhanced as pointed out on the Usenet
news. The first trick (%%~fa) is to ensure that a potential trailing
\ is removed without disturbing the string if the \ is not there.
The second trick (%%~nxa) is ensuring that a critically placed,
potential dot (.) in the string is not dropped. See the References
for more, and the originators.
@echo off & setlocal enableextensions
set debug=true
set mystr=C:\ABC\DEF XYZ\.GHI\
for %%a in ("%mystr%\") do set mystr=%%~fa
if defined debug echo %mystr%
set mystr=%mystr:~0,-1%
if defined debug echo %mystr%
for %%a in ("%mystr%") do set mystr=%%~nxa
if defined debug echo %mystr%
endlocal & goto :EOF
The output will be
D:\TEST>cmdfaq
C:\ABC\DEF XYZ\.GHI\
C:\ABC\DEF XYZ\.GHI
.GHI
In the old days when the proverbial "we" programmed in straight
MS-DOS batch we relied a lot on the peculiarities of the DOS batch
syntax. When the versions changed, some of the tricks no longer
worked. The above has some resemblance in the sense that it assumes
that the %~fa trick will stay. A nice and an inventive solution,
nevertheless.
A more generic option to handle the trailing bakcslash \ is
@echo off & setlocal enableextensions
set debug=true
set mystr=C:\ABC\\DEF XYZ\.GHI\
if defined debug echo %mystr%
set mystr=%mystr%\
if defined debug echo %mystr%
set mystr=%mystr:\\=\%
if defined debug echo %mystr%
set mystr=%mystr:~0,-1%
if defined debug echo %mystr%
for %%a in ("%mystr%") do set mystr=%%~nxa
if defined debug echo %mystr%
endlocal & goto :EOF
producing the following output
D:\TEST>cmdfaq
C:\ABC\\DEF XYZ\.GHI\
C:\ABC\\DEF XYZ\.GHI\\
C:\ABC\DEF XYZ\.GHI\
C:\ABC\DEF XYZ\.GHI
.GHI
Another demonstration
@echo off & setlocal enableextensions disabledelayedexpansion
:: Get the string to be parsed
set MyArguments=%~1
if "%~1"=="" set MyArguments=d:\folder 1\folder 2\folder 3\
echo MyArguments=%MyArguments%
::
:: Get the first part and the rest of a variable
for /f "tokens=1,* delims=\" %%a in ("%MyArguments%") do (
set first_=%%a
set rest_=%%b
)
echo first_=%first_%
echo rest_ =%rest_%
::
:: Get the last part of a variable
set rest_=%MyArguments%
:_loop
for /f "tokens=1,* delims=\" %%a in ("%rest_%") do (
set rest_=%%b
set last_=%%a
if defined rest_ goto _loop
)
echo last_=%last_%
endlocal & goto :EOF
The output:
C:\_D\TEST>cmdfaq
MyArguments=d:\folder 1\folder 2\folder 3\
first_=d:
rest_ =folder 1\folder 2\folder 3\
last_=folder 3
Also see the item
144} How do I parse the items from a path like C:\a\b\c\d ?