簡體   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