1

I have a batch script running in windows. Every time the batch script is invoked an input path is provided as a parameter. I need to extract the folder name from the path.For that i need to get the last index of "/" from the path and then take a substring from that path until the end of the string.

Suppose I have a string /home/home1/home2/home3

The output I require is home3. Is there any way to extract the same.

  • In Windows you should use the backslash as path separator, as some commands might have trouble otherwise... – aschipfl Sep 17 '16 at 10:53
  • Do you want _The last index of "/" from the path_ or you want _The last folder name from the path_? The question title indicate that the important data is the _index of a character_, but the last folder _can be extracted_ without using an index! I suggest you to focus your questions on the _real problem_ (like "folder name") and not insert unrelated data (like "index of a char"). – Aacini Sep 17 '16 at 14:13

2 Answers2

3

For plain DOS/Windows batch files, this should work:

set FILE="c:\foo\bar.txt"
for /F %%i in ("%FILE%") do @echo %%~ni

That comes from DOS BAT file equivalent to Unix basename command?

Windows PowerShell and the Unix shell offer other alternatives.

Community
  • 1
  • 1
Todd Knarr
  • 1,255
  • 1
  • 8
  • 14
  • Thank you Todd! :) – Suraj Menon Sep 17 '16 at 06:37
  • Not only is /F not necessary, it will cause problems if the path has spaces in it, unless DELIMS is set to nothing. Also, it should be `%%~nxi`, as folder names can include dots. – dbenham Sep 17 '16 at 12:11
  • This will fail if the original path has a trailing backslash. There are additional esoteric edge cases. See [my answer](http://stackoverflow.com/a/39547800/1012053) – dbenham Sep 17 '16 at 14:22
2

So you have a string representing a folder path, and you want the name of the right most folder within the path. CMD.EXE provides convenient tools to work with file/folder paths, so there is no need to search for the last \.

You don't state where the string resides. Most likely it is either 1) in a batch parameter from a CALL to a batch script or :function, or 2) within an environment variable. I will assume a parameter, and show a succession of solutions, each one better (more robust) than the prior one. At the very end I will show a slight twist to adapt to working with an environment variable.

So if parameter %1 contains /home/home1/home2/home3, then all you need is %~n1.

But folder names can include dots, and the text after the last dot is considered to be an extension. So you need the x modifier as well to include the extension. For example, if %1 contains /home.1/home.2/home.3, then %~nx will yield home.3. It works just as well if there is no extension.

But folder names can include a poison character like &, so you should enclose the string in quotes: "%~nx1". If you are assigning the result to a variable, then you should enclose the entire assignment in quotes: set "folder=%~nx1". The value will not include the quotes, so be sure to add quotes when expanding the variable: "%folder%", or else use delayed expansion !folder!.

But sometimes people include a trailing backslash when passing a folder path, as in \home1\home2\home3\. The trailing backslash positively indicates that the path is to a folder, but %~nx1 will yield nothing. There is a simple trick using a FOR loop and an appended dot to solve this.

for %%F in (%1.) do set "folder=%%~nxF"

Note that FOR variables use the exact same modifiers as parameters. The appended dot elegantly solves the problem in a tricky way. If there is a trailing backslash, then the dot represents the "current" directory from that postion. The expansion modifiers automatically normalize the result into a canonical form, which yields the correct answer. But it also works if there is not a trailing backslash. File and folder names are not allowed to end with a dot or a space, and the expansion normalization will strip the trailing dot.

There are a few other esoteric cases dealing with UNC paths and long paths that are solved by adding the ~f modifier to convert %1 into the full canonical path.

Here is the ultimate solution that should "always" work with batch parameter %1.

for %%F in ("%~f1.") do set "folder=%%~nxF"

I put the word "always" in quotes because it is possible for the code to fail, but it would require the end user doing something stupid like passing "c:\This"^&"that\". In this case, the correct thing to do is simply pass "c:\This&that\".

Note that the passed path could be the root of a volume, like "c:\". In this case the result is an empty string, which is correct - there is no folder name.

How to work with an environment variable instead

Suppose you have variable folderPath that contains the path string. If you know that the value does not contain any quotes, and it is not a UNC or long path, then you can simply use:

for %%F in ("%folderPath%.") do set "folder=%%~nxF"

But that can fail in multiple ways if the value already contains quotes, or if it is a UNC or long path. The solution is to add an extra FOR /F loop coupled with delayed expansion to safely transfer the value into a FOR variable. Then the ~f modifier can be used as before. But paths can include the ! character, and FOR variable expansion will strip any ! if delayed expansion is enabled. So delayed expansion must be strategically toggled on and off.

Here is the ultimate solution for working with a variable

I'm assuming that delayed expansion is currently off.

setlocal enableDelayedExpansion
for /f "eol=: delims=" %%A in ("!folderPath!") do (
  endlocal
  for %%F in ("%%~fA.") do set "folder=%%~nxF"
)

I'm not aware of any scenarios where this last code can fail.

dbenham
  • 127,446
  • 28
  • 251
  • 390