批处理脚本以递归方式重命名文件夹,其中路径包含变量字符串

时间:2018-06-15 03:08:15

标签: batch-file

我有一个脚本,可以从锚点位置(C:\ Temp \ Corporate Services)处理文件夹结构。对于树中的每个文件夹,如果路径包含单词Registers,那么我需要将寄存器下面的所有子文件夹作为前缀(Reg)。 以下是树的示例 - 有400家公司具有相同的文件夹结构如下:

> tree
C:.

└───Temp
    └───Corporate Services
        ├───Company A
        │   ├───Agreements
        │   │   ├───2017
        │   │   └───2018
        │   └───Registers
        │       ├───2016
        │       ├───2017
        │       └───2018
        │           └───Folder1
        │               └───Folder2
        └───Company B
        │   ├───Agreements
        │   │   ├───2017
        │   │   └───2018
        │   └───Registers
        │       ├───2016
        │       ├───2017
        │       └───2018
        │           └───FolderX
        │               └───Folder Y
        └───Company C...

因此,如果完整路径为C:\ Temp \ Corporate Services \ Registers \ 2016,则需要将2016文件夹重命名为(REG)2017。 2017年和2018年相同。编辑:树可以延伸到年份文件夹以外的其他子文件夹,因此也需要重命名。

我已经设法通过树递归了但是在分析'registers'字符串的路径时卡住了。任何帮助将非常感激。

@echo off
set /A o=0
echo o starts as %o%

call :treeProcess
rem goto:eof

:treeProcess
setlocal enabledelayedexpansion
set /A i=1
REM echo i is %i%

for /f "tokens=*" %%f in ('dir /ad /s /b "C:\Temp\Corporate Services"') do (

echo root: %%f


for /D %%d in (*) do (

    cd %%d


    Set str1=%%~f
    Set var=%str1:registers=%
    echo %var%

    REM if not "%var%"==%str1% echo found reg

    set /A o=%i%+1

    if %o%==2 goto :eof 
    if %o%==1 call :treeProcess
    cd ..
    )
ENDLOCAL
        )
:eof
exit /b 0

3 个答案:

答案 0 :(得分:1)

  • 以下批次中的SearchDir可能看起来不对,
    但是Dir /B/S/AD从给定路径开始并递归搜索最后一个元素 - 因此只能有效地返回匹配的文件夹
  • 这是for /d枚举文件夹的起点。
  • echo to findstr确保不再处理前缀为(REG)的文件夹。
  • 技术上是一个单行程,当用%%
  • 替换%时,可以在cmd行中执行
:: Q:\Test\2018\06\15\SO_50868596.cmd
@Echo off
set "SearchDir=C:\Temp\Corporate Services\Registers"

For /f "Delims=" %%A in ('Dir /B/S /AD "%SearchDir%"') Do For /D %%B in ("%%A\*"
) Do Echo=%%~nxB|findstr /i "^(REG)" 2>&1>NUL || Ren "%%~fB" "(REG)%%~nxB"

示例树输出:

> tree
C:.

└───Temp
    └───Corporate Services
        ├───Company A
        │   ├───Agreements
        │   │   ├───2017
        │   │   └───2018
        │   └───Registers
        │       ├───(REG)201
        │       ├───(REG)201
        │       └───(REG)201
        └───Company B

答案 1 :(得分:0)

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
 'dir /b /s /ad "%sourcedir%\*" '
 ) DO (
  FOR /L %%y IN (2016,1,2018) DO (
   IF "%%~na" == "%%y" FOR %%p IN ("%%~dpa.") DO IF /i "%%~np"=="Registers" ECHO(REN "%%a" "(REG)%%y"
  )
 )
)

GOTO :EOF

您需要更改sourcedir的设置以适合您的具体情况。

为了测试目的,所需的REN命令仅为ECHO在您确认命令正确后,将ECHO(REN更改为REN以实际重命名文件。

首先,执行目录扫描,对于找到的每个目录,检查“名称”部分(%%~na)是否为目标年份%%y之一。

如果是,则如果父目录的名称部分是“注册”,则重命名。

哦 - 顺便说一句 - 在::-Comments(括号内的行序列)中使用code block不是一个好主意,因为::是一个可以打破阻塞的标签。在REM中使用code blocks

哦 - 刚刚意识到你想要重命名所有子目录,而不仅仅是2016..2018

更简单的代码:

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
 'dir /b /s /ad "%sourcedir%\*" '
 ) DO (
  FOR %%p IN ("%%~dpa.") DO IF /i "%%~np"=="Registers" ECHO(REN "%%a" "(REG)%%~na"
 )
)

GOTO :EOF

答案 2 :(得分:0)

你的代码有几个缺陷;其中一些是:

  • 您正在写入并读取同一代码块(str1varo)中的变量,这需要delayed expansion;
  • 此处/R的开关dir完全不需要(我猜你对备用数据流不感兴趣);
  • 你试图以递归方式调用子例程:treeProcess(自己调用它),这可能在某些情况下有效,但在这里不行,因为你已经递归地枚举了所有(子)目录({ {1}})无论如何;递归调用非常危险,例如,您可能很容易达到嵌套限制;
  • 你不应该在代码块中使用dir /S - 样式的注释,因为它们可能会导致意外的结果;
  • 有一个(注释掉的)::,应该是call :EOF;
  • 对引用的字符串与未引用的字符串进行了(注释掉)goto :EOF比较,因此它永远不会成为现实;

无论如何,由于您只想重命名某个层次结构级别的目录,我建议不要使用递归以避免意外更改。相反,我只会处理专用的子目录中的目录:

if

修改

要处理曾祖母的子目录,您可以使用以下代码:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_ROOT=C:\Temp\Corporate Services"
set "_NAME=Registers"
set "_PREF=(REG)"

rem // Enumerate immediate child directories of root directory:
for /D %%A in ("%_ROOT%\*") do (
    rem // Try to change into certain grand-child directory:
    2> nul pushd "%%~A\%_NAME%" && (
        rem // Enumerate grand-grand-child directories and filter them:
        for /F "delims=" %%C in ('
            2^> nul dir /B /A:D "*" ^| findstr /I /V /B /C:"%_PREF%"
        ') do (
            rem // Rename directories that have not yet been:
            ECHO ren "%%~C" "%_PREF%%%~C"
        )
        rem // Return from grand-child directory:
        popd
    )
)

endlocal
exit /B