Windows批处理文件:从路径中获取最后一个文件夹名称

3
我正在尝试重命名e:\study\pubpmc\test\extracted目录下的一个子目录中的.jpg文件。
我想将文件重命名为LastFolderName_ImageName.jpg。 (例如,如果Figure1.jpg位于e:\study\pubpmc\test\extracted\folder1中, 我希望它被重命名为folder1_Figure1.jpg)
因此,我需要从文件路径中取出最后一个文件夹的名称。由于这是我的第一次批处理脚本编写,我很难做到这一点。
我在谷歌上搜索了相关代码,但似乎无法正常运行。
你能帮我看看哪里有问题吗? 谢谢! :)
@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


)
4个回答

3

JosefZ解释了您的代码存在的明显问题,但他未指出一个微妙的问题,尽管他的代码修复了它:

FOR /R(以及简单的FOR)会在扫描磁盘驱动器完成之前立即开始迭代。循环可能会重新迭代已命名的文件!这将导致它被重命名两次,从而产生错误结果。解决方法是使用带有命令“DIR /B”的FOR / F,因为FOR / F始终在迭代之前完全处理命令。

JosefZ还提供了适用于大多数情况的代码。但有一个更简单的解决方案,始终有效:

@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"
"%%A\.."将文件名视为文件夹并向上遍历到父文件夹。因此,%%~nxB给出了父文件夹的名称。
该命令可以作为长行命令直接从命令行运行(不需要批处理):
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"

2
  1. 避免在 (括号中的命令块) 内使用 :label:: label-like comment。在括号内使用它们 - 包括 FORIF 命令 - 将破坏它们的上下文
  2. (括号中的命令块) 中使用变量。阅读 EnableDelayedExpansion:延迟扩展将导致变量在执行时间而不是在解析时间扩展[CLI会一次解析所有的(括号中的命令块)]。

下一个脚本应该适合您。请注意,rename 语句仅用于调试目的而被 echo

@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

资源:

1
好的解释,除了你没有解释如何使用简单的FOR或FOR /R重新处理已命名的文件(这是不好的)。你的解决方案存在潜在问题。 1) 如果路径包含“!”,延迟扩展会破坏FOR变量扩展。 2) 你应该使用"delims ="而不是"tokens = *",因为名称可能以空格开头。 3) 目前编写的默认值eol =;如果文件名以;开头,将会导致问题。 - dbenham
@dbenham 1) 我只是提供了一个信息性链接EnableDelayedExpansion,但在脚本中,即使在原始代码中也可以读取_DisableDelayedExpansion_(为另一个严重错误进行编辑:rename命令目标中的驱动器和路径)。2)3) 被毫无保留地接受。然而,我总是欣赏您启发性和友好的批评... - JosefZ
抱歉,我没有仔细阅读禁用延迟扩展。我匆忙地浏览了代码,看到了enableextensions之前的部分,以及结尾处的expansion,就得出了错误的结论。 - dbenham
对于在 (..) 循环内插入 :: 注释的警告,我给予加一分。这个问题曾经让我犯过错误(但并不是太多次!)。批处理文件没有产生错误消息,但是已经损坏了! - rossmcm

0
我已经为此编写了一个函数。您可以将任何路径传递给它,它将返回文件名或路径名。适用于任何路径:Url、Windows路径、Linux路径等等...

将此函数复制到批处理脚本的末尾:(以下是说明)

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 ===========================================================================

使用方法:

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

结果:文件夹1。

似乎无法正常工作 - undefined

0

如果您的程序或com文件在重命名时遍历这些文件夹,则应该能够获取当前工作目录(路径),pwd。您可以通过创建PREVIOUS_FOLDER并执行字符串替换,将除LAST_FOLDER之外的所有内容都切掉。

或者,您可以将pwd中的文件夹名称在“\”标记处断开成一个数组,并使用-1数组引用来获取最后一个文件夹名称。

在任何情况下,您都需要检查当前工作目录命令。

如果您正在创建所有这些的大型文本列表,并发出对批处理文件的单个调用。

那么您可能最好使用类似以下内容的东西:(Symmantic代码警告) (copy) /folderbase/some_folder/oneormore1/image_from_oneormore1.jpg (to) /folderbase/some_folder/oneormore1/oneormore1_image_from_oneormore1.jpg

而不是复制,Windows使用重命名,Linux使用mv。

后一个示例只需要创建一个重复的列表,并在解析标记时将\替换为_。

您提供的代码很难理解,因此很难确定是否可以简单地串联当前文件夹和图像名称(字符串化),然后将它们写入或重命名为它们所在的位置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接