<http://www.netikka.net/tsneti/info/tscmd080.htm>
Copyright © 2003-2010 by Prof. Timo Salmi  
Last modified Thu 22-Apr-2010 10:10:43

 
Assorted NT/2000/XP/.. CMD.EXE Script Tricks
From the html version of the tscmd.zip 1cmdfaq.txt file
To the Description and the Index
 

This page is edited from the 1cmdfaq.txt faq-file contained in my tscmd.zip command line interface (CLI) collection. That zipped file has much additional material, including a number of detached .cmd script files. It is recommended that you also get the zipped version as a companion.

Please see "The Description and the Index page" for the conditions of usage and other such information.



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 ?

References/Comments: (If a Google message link fails try the links within the brackets.)
  Google Groups Dec 31 2004, 3:39 am [M]
  Google Groups Dec 31 2004, 5:44 am [M]
  Google Groups Jan 1 2005, 1:51 am [M]