0

How do I get relative directories / partial paths to display as echo output from a windows .bat file?

How to split the filename from a full path in batch?

Talks about everything but.

I've found drive letters, filenames, extensions, shortened (8.3) names, and full paths - but no relative paths.

I'm running a recursive FOR /R loop; which traverses sub-directories. I would like something - that doesn't have twenty characters of useless path info - that tells me which directory each duplicate file lives in... without hardcoding the .bat file to live in a certain directory/path?

Maybe a solution would be to measure the length of the script's path and cut that off of the front of the full path? But I don't know how to manipulate that.

Script could be in many locations:

F:\a.bat<BR>
F:\Dir1\fileA.txt<BR>
F:\Dir20\fileA.txt

C:\Users\Longusername\Desktop\Container\a.bat<BR>
C:\Users\Longusername\Desktop\Container\Dir1\fileA<BR>
C:\Users\Longusername\Desktop\Container\Dir20\fileA

And right now the only options I have for output are (%%~nxG):

fileA.txt
fileA.txt

Which doesn't tell me which directory each file is in...or (%%~pnxG)

\Users\Longusername\Desktop\Container\Dir1\fileA.txt
\Users\Longusername\Desktop\Container\Dir20\fileA.txt

What I'd like, from any location:

\Dir1\fileA.txt
\Dir20\fileA.txt

Could be missing the leading \, but that's negligible. Other options than echo are permissible if they'll work on most window machines. They may lead to more questions, though - as I've figured out my other pieces with echo.

Stephan
  • 53,940
  • 10
  • 58
  • 91
user3082
  • 103
  • 3

3 Answers3

3

quite easy, if you think about it: just remove the current directory path (%cd%):

@echo off 
setlocal enabledelayedexpansion
for /r %%a in (*.txt) do (
  set "x=%%a"
  echo with \:    !x:%cd%\=\!
  echo without \: !x:%cd%\=!
)

By the way: \folder\file always refers to the root of the drive (x:\folder\file), so it's not exactly a relative path.

Stephan
  • 53,940
  • 10
  • 58
  • 91
2

This is similar to the already accepted answer, but with delayed expansion enabled only where needed. This should correctly output filenames containing ! characters.

@Echo Off
SetLocal DisableDelayedExpansion

Set "TopLevel=C:\Users\LongUserName"

For /R "%TopLevel%" %%A In ("*.txt") Do (
    Set "_=%%A"
    SetLocal EnableDelayedExpansion
    Echo=!_:*%TopLevel%=!
    EndLocal
)

Pause

You could also use Set "TopLevel=%~dp0", (the running script's directory) or Set "TopLevel=%~dp0..", (the running script's parent directory)


One potential benefit of the above method is that you can also use a location relative to the current directory for the value of %TopLevel% too, (in this case, based upon the initial example, the current directory would be C:\Users):
Set "TopLevel=LongUserName"

Although this would only work correctly if LongUserName didn't already exist as content of the path earlier in the tree.

Compo
  • 36,585
  • 5
  • 27
  • 39
2

You could use xcopy together with its /S (include sub-directories) and /L (list but do not copy) options since it returns relative paths then, so you do not have to do any string manipulation, which might sometimes be a bit dangerous, particularly when the current directory is the root of a drive:

xcopy /L /S /I /Y /R ".\*.txt" "\" | find ".\"

The appended find command constitutes a filter that removes the summary line # File(s) from the output.


To capture the output of the aforementioned command line just use a for /F loop:

for /F "delims=" %%I in ('
    xcopy /L /S /I /Y /R ".\*.txt" "\" ^| find ".\"
') do (
    rem // Do something with each item:
    echo/%%I
)
aschipfl
  • 33,626
  • 12
  • 54
  • 99