繁体   English   中英

Windows批处理文件和正则表达式:重命名所有没有给定字符串的文件夹

[英]Windows batch file and regex: rename all folders without given string

情况:

我有许多文件夹,其名称类似于电子邮件地址,例如username@domain.tld。 必须将这些文件夹重命名为用户名。 所以直到“@”的所有字符都是我给定的字符串。 (没有“@”)

目前的文字名称:

  • username1@domain.tld
  • username2@domain.tld

请求的foldernames:

  • USERNAME1
  • USERNAME2

问题:

  1. 我的正则表达式是错误的,即使使用正则表达式生成器,我也无法做到正确。
  2. 即使我有正确的正则表达式我不知道,我将如何重命名正确的方式(参见for循环)。

谢谢你的帮助!

@ECHO off
SETLOCAL ENABLEDELAYEDEXPANSION

SET pathMail="C:\Users\Username\Desktop\Batchtest\Folderstructure"
PUSHD %pathMail%

ECHO "::Extract string from folder"
FOR /f %%G in ('DIR /b /ad ^| FINDSTR /r "[a-z].*[^@]"') DO (
    ::wrong logic!?
    REN %%G=%%G
)

POPD
:EOF

您可以使用单行(UNTESTED)来执行此操作:

for /f "delims=@ tokens=1*" %a in ('dir /s /ad /b *@*') do @echo ren %a@%b %~nxa

这个怎么运作:

  1. dir /b /ad /s *@*命令为包含@的所有文件夹生成一个完整路径名的裸列表。

  2. delims=@选项将每一行分成两行:@之前的第一部分和@之后的第二部分。

  3. ren命令将完整路径名重命名为@之前的部分。 %~nxa只从完整路径中提取名称(和任何扩展名)。

  4. echo命令就在那里,这样你就可以看到它将要做什么。 一旦你满意,它会做正确的事情,删除它。

NB

如果从批处理文件中运行此操作,而不是以交互方式运行,请使用%%而不是%

findstr返回整行,如果它包含匹配,而不是匹配的部分,所以你需要在编程后拆分@字符和所有内容。

您不需要在setlocal / endlocal块中使用pushdpopd ,因为后者也会对当前工作目录进行本地化。

避免使用像:: block ()代码中的错误标签备注,因为它们可能会造成麻烦!

以下代码执行您想要的操作:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "pathMail=C:\Users\Username\Desktop\Batchtest\Folderstructure"
cd /D "%pathMail%"

for /F %%G in ('
    dir /B /A:D "?*@*" ^| findstr /I /R "^[a-z][^@]*@[^@][^@]*$"
') do (
    set "ITEM=%%G"
    setlocal EnableDelayedExpansion
    call :LEN ILEN ITEM
    set "RIGHT=!ITEM:*@=!"
    call :LEN RLEN RIGHT
    for /F "delims=" %%N in ('set /A "ILEN-=!RLEN!+1"') do (
        rem Remove `ECHO` to actually rename any directories:
        ECHO ren "%%G" "!ITEM:~,%%N!"
    )
    endlocal
)
endlocal
exit /B

:LEN output input
setlocal EnableDelayedExpansion
set /A "SLEN=0"
if "%~2"=="" goto :END
set "STRING=!%~2!"
if not defined STRING goto :END
set /A "SLEN=1"
for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
    if not "!STRING:~%%I!"=="" (
        set /A "SLEN+=%%I"
        set "STRING=!STRING:~%%I!"
    )
)
:END
if "%~1"=="" (
    echo(%SLEN%
    endlocal
) else (
    endlocal & set "%~1=%SLEN%"
)
exit /B

怎么了:

  • 如上所述, cdpushd / popd替换为setlocal / endlocal就足够了;
  • findstr用于仅返回名称以字母开头的目录,后跟任意数量的不包含@的字符,后跟@字符,后跟至少一个除@以外的字符;
  • 子程序:LEN调用:LEN来确定当前目录名的长度(字符数),结果存储在变量ILEN ;
  • 从目录名中删除包含@所有内容(通过子字符串替换语法),结果由变量RIGHT ;
  • 子程序:LEN调用:LEN来确定RIGHT字符串的长度,结果赋予变量RLEN ;
  • 两个长度数减1之间的差值由set /A计算,结果用于获取@符号之前的字符串部分(通过子字符串扩展语法);

代码看起来有点复杂,特别是因为切换延迟扩展,计算字符串长度而不是使用智能子字符串替换语法并将变量名称而不是字符串值传递给子例程。 但是,所有这些都是为了避免使用包含特殊字符的目录名称的麻烦! %=

这种方法的巨大优势在于它甚至可以用于由不止一个字符组成的符号(假设dirfindstr模式相应地进行了调整)。


如果保证在目录名中不能出现字符^% ,则以下代码可以正常工作并且更简单一些( "也可能是有害字符,但无论如何都禁止使用file / dir。”):

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "pathMail=C:\Users\Username\Desktop\Batchtest\Folderstructure"
cd /D "%pathMail%"

for /F %%G in ('
    dir /B /A:D "?*@*" ^| findstr /I /R "^[a-z][^@]*@[^@][^@]*$"
') do (
    call :SUB ITEM "%%G"
    rem Remove `ECHO` to actually rename any directories:
    call ECHO ren "%%G" "%%ITEM%%"
)
endlocal
exit /B

:SUB output %input%
set "LEFT=%~2"
if not defined LEFT goto :EOF
set "LEFT=%LEFT:@=" & rem "%"
if "%~1"=="" (
    echo "%LEFT%"
) else (
    set "%~1=%LEFT%"
)
goto :EOF

核心函数是子程序中的子串替换黑客set "LEFT=%LEFT:@=" & rem "%" :SUB ,它删除了@符号及其后的所有内容。 这种方法的积分转到Aacini - 请看这篇文章


为了完整起见,这是一个简单的解决方案,仅当符号由单个字符( @ )组成时才有效:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "pathMail=C:\Users\Username\Desktop\Batchtest\Folderstructure"
cd /D "%pathMail%"

for /F "eol=| delims=" %%G in ('
    dir /B /A:D "?*@*" ^| findstr /I /R "^[a-z][^@]*@[^@][^@]*$"
') do (
    for /F "eol=| delims=@" %%N in ("%%G") do (
        rem Remove `ECHO` to actually rename any directories:
        ECHO ren "%%G" "%%N"
    )
)
endlocal
exit /B

它是Klitos Kyriacou方法的改进版本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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