【问题标题】:Windows batch file: get last folder name from pathWindows批处理文件:从路径获取最后一个文件夹名称
【发布时间】:2015-03-29 09:35:26
【问题描述】:

我正在尝试重命名位于 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


)

【问题讨论】:

    标签: batch-file


    【解决方案1】:

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

    FOR /R(以及简单的 FOR)在完成磁盘驱动器扫描之前立即开始迭代。循环可能会重复已命名的文件!这将导致它被重命名两次,从而给出错误的结果。解决方案是将 FOR /F 与命令“DIR /B”一起使用,因为 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. 避免在(command block in parentheses) 中使用:label:: label-like comment。在括号内使用它们中的任何一个 - 包括 FORIF 命令 - will break their context
      2. (command block in parentheses) 中使用变量。阅读EnableDelayedExpansion:延迟扩展将导致变量在执行时间而不是在解析时间被扩展[并且CLI一次解析所有(command block in parentheses)]

      下一个脚本应该适合你。注意rename 语句仅仅是echoed 用于调试目的。

      @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
      

      资源:

      【讨论】:

      • 很好的解释,除了你错过了解释简单的 FOR 或 FOR /R 如何重新处理已经命名的文件(一件坏事)。您的解决方案存在潜在问题。 1) 如果路径包含 !,延迟扩展会损坏 FOR 变量扩展。 2) 您应该使用"delims=" 而不是"tokens=*",因为名称可以以空格开头。 3) 如目前所写,如果文件名以; 开头,默认的eol=; 将导致问题。
      • @dbenham 1) 我只提供了一个指向 EnableDelayedExpansion 的信息链接,但在脚本中你可以阅读即使在原始代码中声明的 DisableDelayedExpansion(已编辑另一个严重错误:rename 命令目标中的驱动器和路径)。 2)3) 无保留接受。但是,我始终感谢您的启发性和友好的批评...
      • 糟糕 - 抱歉,我没有仔细阅读 disabledelayedexpansion。我快速浏览了代码,在extensions 之前看到了enable,最后是expansion,并得出了错误的结论。
      • +1 用于在 (..) 循环中插入 :: cmets 的警告。这不止一次抓住了我(但不是太多次!)。批处理文件不产生错误消息但已损坏!
      【解决方案3】:

      我已经为此编写了一个函数。你给它任何路径,它只返回它的文件名或路径名。适用于任何路径: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

      【讨论】:

        【解决方案4】:

        如果你的程序或com文件在重命名时遍历了这些文件夹,那么它应该能够得到当前的工作目录(path),pwd。您还可以通过创建 PREVIOUS_FOLDER 并进行字符串替换来删除除 LAST_FOLDER 之外的所有内容。

        或者您可以将 pwd 中的 '\' 标记处的文件夹名称分解为一个数组,并使用 -1 数组引用来获取最后一个文件夹名称。

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

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

        那么你可能会更好: (符号代码警告) (复制)/folderbase/some_folder/oneormore1/image_from_oneormore1.jpg (到)/folderbase/some_folder/oneormore1/oneormore1_image_from_oneormore1.jpg

        window使用rename代替copy,linux使用mv。

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

        您给出的代码很难理解,因此很难辨别您是否可以简单地连接当前文件夹和图像名称(字符串化),然后在它们所在的位置写入或重命名它们。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-05-17
          • 2013-06-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多