简体   繁体   中英

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

Situation:

I have many folders which are named like an email-address, eg username@domain.tld. These folders has to be renamed into just the username. so all characters until the "@" is my given string. (without the "@")

Current foldernames:

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

Requested foldernames:

  • username1
  • username2

Problem:

  1. My Regex is wrong and even with the regex generator I can't get it right.
  2. Even if I have the right Regex I do not know, how I shall rename the right way (see at for loop).

Thank you for every help!

@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

You might be able to do it with a one-liner (UNTESTED):

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

How it works:

  1. The dir /b /ad /s *@* command produces a bare listing of full pathnames for all folders containing a @.

  2. The delims=@ option splits each line into two: the first part before the @, and the second part after the @.

  3. The ren command renames the full pathname to the part before the @. The %~nxa just extracts the name (and any extension) from the full path.

  4. The echo command is there, just so you can see what it's going to do. Once you're satisfied it will do the right thing, remove it.

NB

If you run this from a batch file, instead of interactively, use %% instead of % .

findstr returns the entire line if it contains a match, not the matching part only, so you need to split off the @ character and everything after programmatically.

You do not need to use pushd and popd within a setlocal / endlocal block because, the latter localises the current working directory too.

Avoid wrong-label remarks like :: within blocks () of code, because they may cause trouble!

The following code does what you want:

@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

What happens:

  • cd replaces pushd / popd as setlocal / endlocal suffices as aforementioned;
  • findstr is used to return only directory whose names start with a letter, followed by any number of characters not containing @ , followed by the @ character, followed by at least one character other than @ ;
  • the subroutine :LEN is called to determine the length (number of characters) of the current directory name, the result is stored in variable ILEN ;
  • everything up to and including the @ is removed from the directory name (by substring replacement syntax), the result is held by variable RIGHT ;
  • the subroutine :LEN is called to determine the length of the string in RIGHT , the result is given to variable RLEN ;
  • the difference between the two length numbers minus 1 is calculated by set /A , the result is used for getting the string portion before the @ symbol (by substring expansion syntax);

The code looks a bit complicated, especially because of toggling delayed expansion, computing string lengths rather than using intelligent substring replacement syntax and passing variable names rather than string values to the subroutine. However, all this has been done to avoid trouble with directory names which contain special characters like ! , % , = , etc.

The great advantace of this approach is that it works even for symbols that consist of more than just a single character (supposing the dir and findstr patterns are adapted accordingly).


If it is guaranteed that the characters ^ and % cannot occur in the directory names, the following code works fine and is a bit simpler ( " would also be a harmful character but this is prohibited for file/dir. names anyway):

@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

The core function is the substring replacement hack set "LEFT=%LEFT:@=" & rem "%" in the subroutine :SUB , which removes the @ sign and everything after. Credits for this method go to Aacini -- see this post .


For the sake of completeness, here is a simple solution that works only if the symbol consists of a single character ( @ ):

@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

It is an improved variant of Klitos Kyriacou's approach .

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