C:\ABC\DEF\GHI\
C:\ABC\XYZ\
I want to extract "GHI" and "XYZ"
I can use something like:
FOR /F "tokens=4 delims=\" %%i IN ("C:\ABC\DEF\GHI\") DO @ECHO %%i
But the same line wouldn't work for C:\ABC\XYZ\
I want it to be dynamic.
set p=c:\abc\xyz\
This will remove a trailing \, if present, and display
the name:
set p=%p%::::
set p=%p:\::::=%
for %%a in ("%p%") do echo %%~na
If you know the path to be a valid path on your system
use the fact that cd'ing to a folder will remove the
trailing \ so the above three lines can be reduced to:
cd %p%
for %%a in ("%cd%") do echo %%~na
I don't want to remove a trailing "\"
I want to return the last directory in the path
example:
"C:\ABX\XYZ\" would return "XYZ"
"C:\ABC\DEF\GHI\" would return "GHI"
ggroth...@volcanomail.com wrote in news:1104379136.199835.47600
@f14g2000cwb.googlegroups.com:
pinout <no...@none.none> wrote in news:Xns95CED5263EEBFpinout@
204.127.199.17:
for %a in (c:\abc\def\ghi) do echo %~na
--
Phil Robyn
Univ. of California, Berkeley
u n z i p m y a d d r e s s t o s e n d e - m a i l
Demo:
@echo off & setlocal enableextensions
set p1=C:\ABC\DEF\GHI\
echo %p1%|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 %p1%
echo %last%
endlocal & goto :EOF
The output
D:\TEST>cmdfaq
C:\ABC\DEF\GHI\
GHI
And with p1=C:\ABC\XYZ\
C:\ABC\XYZ\
XYZ
All the best, Timo
--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland
Useful script files and tricks ftp://garbo.uwasa.fi/pc/link/tscmd.zip
> for %a in (c:\abc\def\ghi) do echo %~na
That's very need, especially compared with the multi-line
script-only solution I just came up with. Nevertheless, there might
be something instructive in that more generic, lengthy solution, so
I'll post that too below:
@echo off & setlocal enableextensions enabledelayedexpansion
set mystr=C:\ABC\DEF\GHI\
:: 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%!
echo %result%
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
Output
D:\TEST>cmdfaq
C:\ABC\DEF\GHI
GHI
All the best, Timo
Or, prudently
for %a in ("c:\abc\def\ghi") do echo %~na
See what would obviously happen if we had
for %a in (c:\abc\def xyx\ghi) do echo %~na
set p=c:\abc\ghi\
Strip the trailing character in the set command and then
use a for command making use of the %%~na notation which
extracts the name:
set p=%p:~0,-1%
> In article <33hr60F...@individual.net>,
> Phil Robyn <zipp...@berkeley.edu> wrote:
>
>>pinout wrote:
>>
>>>>"C:\ABX\XYZ\" would return "XYZ"
>>>>"C:\ABC\DEF\GHI\" would return "GHI"
>>
>>for %a in (c:\abc\def\ghi) do echo %~na
>
>
> Or, prudently
> for %a in ("c:\abc\def\ghi") do echo %~na
>
> See what would obviously happen if we had
> for %a in (c:\abc\def xyx\ghi) do echo %~na
>
> All the best, Timo
>
Hi, Timo,
Yes, of course it is best to use double quotes in case of
space(s) in the path. Hope you have a Happy New Year!
I have examined the examples so far and found varying results.
One only works if the path contains the trailing backslash, while another
only works if the trailing backslash was not provided, others only work if
there are no spaces. This solution does not care how the path is provided.
The call commands show how to use the getlast function.
@echo off
call :getlast "C:\ABC\XYZ"
call :getlast "C:\ABC\XYZ\"
call :getlast "C:\ABC\DEF\GHI"
call :getlast "C:\ABC\DEF\GHI\"
call :getlast "C:\ABC\DEF def\GHI\"
call :getlast "C:\ABC\DEF\GHI ghi\"
call :getlast "C:\ABC\DEF def\GHI ghi\"
goto:eof
:getlast
:: Stores the last name from spec in variable named "LAST".
:: Syntax:
:: call :getlast C:\ABC\XYZ last=XYZ
:: call :getlast "C:\ABC\X Y Z\" last=X Y Z
:: The echo commands below are for demonstration only.
echo spec=%1
set last=%~1
set last=%last: =:%
set last=%last:\= %
for %%a in (%last%) do set last=%%a
set last=%last::= %
echo LAST=[%last%]
echo.
:: end of batch
--
Todd Vargo (double "L" to reply by email)
> I have examined the examples so far and found varying results.
> One only works if the path contains the trailing backslash, while another
> only works if the trailing backslash was not provided, others only work if
> there are no spaces. This solution does not care how the path is provided.
Actually, (unless I missed something in the testing) while the
method has it disadvantages, the sed/gawk utilizing CMD script
solution which I posted earlier should not have any of those
limitations. Below is the code again, so one does not have to reseek
it.
@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
All the best, Timo
:getlast
echo spec=%1
set last=%1
set last=%last:\=" "%
set last=%last: ""=%
for %%A in (%last%) do set last=%%~A
echo Last=[%last%]
BTW *ALL* the solutions with %~nA deny dots in folder names. It's better
to use %~nxA.
--
Gruesse Greetings Saludos Saluti Salutations
Matthias
---------+---------+---------+---------+---------+---------+---------+
This does not work with c:\
I think that in that case
it should return an empty string.
Here are two solutions that do work in that case
and all other cases mentioned so far. I have also
incorporated Matthias' idea of using ~nxa.
Both solutions assume that the variable p holds the
path and set variable s to the name.
First solution. The three set statements have
the effect of removing a trailing \ if its there
and do no harm if its not. The for extracts the
name.
set s=%p%::::
set s=%s:\::::=%
set s=%s:::::=%
for %%a in ("%s%") do set s=%%~nxa
Second solution. The first for ensures that there is
a \ at the end since %~fa has the effect of reducing
trailing \\ to \. The set removes it and the second
for extracts the name.
for %%a in ("%p%\") do set s=%%~fa
set s=%s:~0,-1%
for %%a in ("%s%") do set s=%%~nxa
In my own batch files I have actually used the
following even shorter solution which I already mentioned (except
here I have modified it to incorporate Matthias' idea)
but since the discussion has turned from the poster's
actual question, which seems to me to imply that there is
a \ at the end, to what is practically
useful in general cases I thought I sould include it here for
completeness. Although this solution requires that p
is an existing path I find that that has always been
the case in the situations where I needed it. This
solutions changes directory to the path in p. The
%cd% variable won't have a trailing \ so we can
just use a for as in the previous solutions.
cd %p%
for %%a in ("%cd%") do set s=%%~nxa
In that case, only a single line needs added to the batch. Insert this line
below the last SET command in the subroutine. This will provide the empty
string if the path is the root.
if %last:~-1%.==. set last=
==== Screen capture
E:\>get_last
spec=\
LAST=[]
spec=C:
LAST=[]
spec=C:\
LAST=[]
spec=C:\ABC
LAST=[ABC]
spec="C:\ABC\XYZ"
LAST=[XYZ]
spec="C:\ABC\XYZ\"
LAST=[XYZ]
spec="C:\ABC\DEF\GHI"
LAST=[GHI]
spec="C:\ABC\DEF\GHI\"
LAST=[GHI]
spec="C:\ABC\DEF def\GHI\"
LAST=[GHI]
spec="C:\ABC\DEF\GHI ghi\"
LAST=[GHI ghi]
spec="C:\ABC\DEF def\GHI ghi\"
LAST=[GHI ghi]
====
Unfortunately, this modification returns the following errors.
spec=C:\
Last=[C:" "] <===error
spec=C:\ABC
Last=[C:" "ABC] <===error
> Actually, (unless I missed something in the testing) while the
> method has it disadvantages, the sed/gawk utilizing CMD script
> solution which I posted earlier should not have any of those
> limitations.
It was not tested here because it requires the 3rd party utility.
(No offence intended.)
> It was not tested here because it requires the 3rd party utility.
> (No offence intended.)
None taken. Sed/gawk-aided script solutions have their obvious pros
and cons.
A strict script-only solution is best achieved by first ensuring
that the trailing \ is either always inserted or always dropped. How
is that, again, done in pure script?
All the best, Timo
--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland
Timo's FAQ materials at http://www.uwasa.fi/~ts/http/tsfaq.html
One way would be to append a backslash then change a double one back to a
single one:
set last=%last%\
set last=%last:\\=\%
/Al
echo c:\aaa\bbb\ccc\ | mtr -o -x+ - (.*\\)([^\\]*)(\\) = \2
returns the "ccc" field, however many precede it. It returns nothing
for echo c:ccc\ but if necessary that could be fixed by putting :
after each of the first two \\ .
There, mtr is MiniTrue, which is probably still at
ftp://ftp.demon.co.uk/pub/mirrors/garbo/pc/fileutil/mtr202b.zip
Possibly SED would do it similarly.
--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME. ©
Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.
I find MiniTrue useful for viewing/searching/altering files, at a DOS prompt;
free, DOS/Win/UNIX, <URL:http://www.idiotsdelight.net/minitrue/> Update hope?
> I already posted 3 different ways of doing that!
Right you are! Something like this will go into my FAQ
@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
References/Comments:
http://www.google.com/groups?selm=1104461083.2...@z14g2000cwz.googlegroups.com
http://www.google.com/groups?selm=cr277b$gg8$00$1...@news.t-online.com
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 soution,
anyway.
All the best, Timo
--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland
I suggest using pushd and popd instead of cd.
Since pushd temporarily assings drive letters to urls like
\\server\share\, even these should work then.
Sorry for the delay, I was ill to bed for some days.
You are right Todd there is a flaw but here the output of my version
is different. If I change to _echo Last=[%last:*:=%]_ it's ok.
Your version has also a problem returning only the drive letter without
colon.
To verify the output of several versions I changed your testbed:
::GetLastDir.cmd:::::::::::::::::::::::::::::::::::::::::::::::::::::
@echo off&setlocal
for %%A in ("C:\"
"%temp%\XYZ"
"%temp%\XYZ\"
"%temp%\DEF\GHI"
"%temp%\DEF\GHI\"
"%temp%\DEF def\GHI.y\"
"%temp%\DEF\GHI ghi\"
"%temp%\DEF def\GHI ghi\"
"\\%COMPUTERNAME%\C\DEF def\GHI ghi\"
) do call :getlast %%A
goto:eof
:getlast
if not exist %1 MD %1
pushd %1
echo spec=[%~1]
echo cd =[%cd%]
for /L %%B in (1 1 4) do call :getlast%%B %*
popd
if %1 NEQ "C:\" rd %1
echo.
pause
goto :eof
:: --- Todd ---
:getlast1
setlocal
set last=%~1
set last=%last: =:%
set last=%last:\= %
for %%a in (%last%) do set last=%%a
set last=%last::= %
echo %0=[%last%]
endlocal&goto :eof
:: --- Matthias2 ---
:getlast2
setlocal
set last=%1
set last=%last:\=" "%
set last=%last: ""=%
for %%A in (%last%) do set last=%%~A
echo %0=[%last:*:=%]
endlocal&goto :eof
:: --- ggrothendieck1 ----
:getlast3
setlocal
set s=%~1::::
set s=%s:\::::=%
set s=%s:::::=%
for %%a in ("%s%") do set s=%%~nxa
echo %0=[%s%]
endlocal&goto :eof
:: --- ggrothendieck2 ----
:getlast4
setlocal
for %%a in ("%cd%") do set s=%%~nxa
echo %0=[%s%]
endlocal&goto :eof
:: --- . ----
:getlast_
setlocal
endlocal&goto :eof
::GetLastDir.cmd:::::::::::::::::::::::::::::::::::::::::::::::::::::
It turns out that even simple tasks fail, if testing falls short.
So creating a testbed, like your modified one above, may be worth
the time.
That was the original version which I provided my own patch for after
ggrothendieck reported the bug with possible corrections.
> :: --- Todd ---
> :getlast1
> setlocal
> set last=%~1
> set last=%last: =:%
> set last=%last:\= %
> for %%a in (%last%) do set last=%%a
> set last=%last::= %
> echo %0=[%last%]
> endlocal&goto :eof
...
Note, my correction(patch), "if %last:~-1%.==. set last=", which I posted
12/31/2004 in response to ggrothendieck's bug report was not included in
your testing.
:: --- Todd ---
:getlast1
setlocal
set last=%~1
set last=%last: =:%
set last=%last:\= %
for %%a in (%last%) do set last=%%a
set last=%last::= %
if %last:~-1%.==. set last=
echo %0=[%last%]
endlocal&goto :eof
> It turns out that even simple tasks fail, if testing falls short.
> So creating a testbed, like your modified one above, may be worth
> the time.
So true.