简体   繁体   中英

Windows batch file: get last folder name from path

I'm trying to rename .jpg files which is in one of many subdirectories of e:\\study\\pubpmc\\test\\extracted.

I want to rename files to LastFolderName_ImageName.jpg. (For example if Figure1.jpg is in e:\\study\\pubpmc\\test\\extracted\\folder1 I want it to be renamed like this: folder1_Figure1.jpg)

So I need to take out the last folder name from the file's path. Since it's my first time with batch scripting, I'm having a hard time.

I googled and made code similar to it but it doesn't seem to work out.

Can you help me with it and tell me where I've done wrong? Thank you! :)

@echo off
cd /D "e:\study\pubpmc\test\extracted"
for /r %%f in (*.jpg) do (
set mydir=%%~dpf
set mydir=%mydir:\=;%

for /f "tokens=* delims=;" %%i in (%mydir%) do call :LAST_FOLDER %%i
goto :EOF

:LAST_FOLDER
if "%1"=="" (
    @echo %LAST%
    goto :EOF
    )

set LAST=%1
SHIFT

goto :LAST_FOLDER


)
  1. Avoid using :label and :: label-like comment inside (command block in parentheses) . Using any of them within parentheses - including FOR and IF commands - will break their context .
  2. Using variables inside (command block in parentheses) . Read EnableDelayedExpansion : Delayed Expansion will cause variables to be expanded at execution time rather than at parse time [and CLI parses all the (command block in parentheses) at once]

Next script should work for you. Note rename statement is merely echo ed for debugging purposes.

@ECHO OFF >NUL
SETLOCAL enableextensions disabledelayedexpansion

set "fromFolder=e:\study\pubpmc\test\extracted"
rem my debug setting set "fromFolder=D:\path"
for /F "tokens=*" %%f in ('dir /B /S /A:D "%fromFolder%\*.*"') do (
    set "mydir=%%~ff"
    set "last=%%~nxf"
    call :renameJPG
)
@ENDLOCAL
goto :eof

:renameJPG
  rem echo "%mydir%" "%last%"
  for /f "tokens=*" %%i in ('dir /B /A:-D "%mydir%\*.jpg" 2^>nul') do (
    echo ren "%mydir%\%%~nxi" "%last%_%%~nxi"
  )
goto :eof

Resources:

JosefZ explains the obvious problems with your code, but he failed to point out a subtle problem, though his code fixed it:

FOR /R (as well as the simple FOR) begin iterating immediately, before it has finished scanning the disk drive. It is possible for the loop to reiterate the already named file! This would cause it to be renamed twice, giving the wrong result. The solution is to use FOR /F with command 'DIR /B', because FOR /F always processes the command to completion before iterating.

JosefZ also provides code that works for most situations. But there is a much simpler solution that works always:

@echo off
for /f "delims=" %%A in (
  'dir /b /s /a-d "e:\study\pubpmc\test\extracted\*.jpg"'
) do for %%B in ("%%A\..") do ren "%%A" "%%~nxB_%%~nxA"

The "%%A\\.." treats the file name as a folder and walks up to the parent folder. So %%~nxB gives the name of the parent folder.

The command could be run as a long one liner, directly from the command line (no batch):

for /f "delims=" %A in ('dir /b /s /a-d "e:\study\pubpmc\test\extracted\*.jpg"') do @for %B in ("%A\..") do @ren "%A" "%~nxB_%~nxA"

If your program or com file traverses these folders when renaming, then it should be able to get the present working directory ( path ), pwd. You may be able to chop everything but the LAST_FOLDER out of this by also creating a PREVIOUS_FOLDER and doing a string replacement.

Or you may be able to break the folder names at the '\\' token from the pwd into an array and use a -1 array reference to get the last folder name.

In any circumstance you'll want to check for a present working directory command.

If your creating a large text list of all these and issuing a single call to the batch file.

Then you may be better off with something like: (Symmantic code warning ) (copy) /folderbase/some_folder/oneormore1/image_from_oneormore1.jpg (to) /folderbase/some_folder/oneormore1/oneormore1_image_from_oneormore1.jpg

Instead of copy, window uses rename, linux uses mv.

The latter example would require simply creating a duplicate list and replacing the \\ with a _ while parsing through the tokens.

The code you've given is difficult to make sense of, so its hard to discern if you can simple concatenate the current folder and image name (stringify) and then write or rename them where they are.

I already wrote a function for that. You give it any path and it returns you only it's filename or pathname. Works for any path: Url, Windows path, Linux path, etc...

Copy this function at the end of your batch script: (Instructions below)

rem ===========================================================================

:Name_From_Path
SetLocal

set _TMP_FOLDERNAME=%1
for %%g in ("%_TMP_FOLDERNAME%") do set _TMP_FOLDERNAME=%%~nxg

EndLocal & set _Name_From_Path=%_TMP_FOLDERNAME%
goto :EOF

rem ===========================================================================

Usage:

CALL :Name_Of_Path e:\study\pubpmc\test\extracted\folder1
ECHO %_Name_From_Path%

Result: folder1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM