[英]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. 我有许多文件夹,其名称类似于电子邮件地址,例如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: 目前的文字名称:
Requested foldernames: 请求的foldernames:
Problem: 问题:
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): 您可以使用单行(UNTESTED)来执行此操作:
for /f "delims=@ tokens=1*" %a in ('dir /s /ad /b *@*') do @echo ren %a@%b %~nxa
How it works: 这个怎么运作:
The dir /b /ad /s *@*
command produces a bare listing of full pathnames for all folders containing a @. dir /b /ad /s *@*
命令为包含@的所有文件夹生成一个完整路径名的裸列表。
The delims=@
option splits each line into two: the first part before the @, and the second part after the @. delims=@
选项将每一行分成两行:@之前的第一部分和@之后的第二部分。
The ren
command renames the full pathname to the part before the @. ren
命令将完整路径名重命名为@之前的部分。 The %~nxa
just extracts the name (and any extension) from the full path. %~nxa
只从完整路径中提取名称(和任何扩展名)。
The echo
command is there, just so you can see what it's going to do. echo
命令就在那里,这样你就可以看到它将要做什么。 Once you're satisfied it will do the right thing, remove it. 一旦你满意,它会做正确的事情,删除它。
NB 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. findstr
返回整行,如果它包含匹配,而不是匹配的部分,所以你需要在编程后拆分@
字符和所有内容。
You do not need to use pushd
and popd
within a setlocal
/ endlocal
block because, the latter localises the current working directory too. 您不需要在
setlocal
/ endlocal
块中使用pushd
和popd
,因为后者也会对当前工作目录进行本地化。
Avoid wrong-label remarks like ::
within blocks ()
of code, because they may cause trouble! 避免使用像
::
block ()
代码中的错误标签备注,因为它们可能会造成麻烦!
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; cd
将pushd
/ popd
替换为setlocal
/ endlocal
就足够了; 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 @
; findstr
用于仅返回名称以字母开头的目录,后跟任意数量的不包含@
的字符,后跟@
字符,后跟至少一个除@
以外的字符; :LEN
is called to determine the length (number of characters) of the current directory name, the result is stored in variable ILEN
; :LEN
调用:LEN
来确定当前目录名的长度(字符数),结果存储在变量ILEN
; @
is removed from the directory name (by substring replacement syntax), the result is held by variable RIGHT
; @
所有内容(通过子字符串替换语法),结果由变量RIGHT
; :LEN
is called to determine the length of the string in RIGHT
, the result is given to variable RLEN
; :LEN
调用:LEN
来确定RIGHT
字符串的长度,结果赋予变量RLEN
; 1
is calculated by set /A
, the result is used for getting the string portion before the @
symbol (by substring expansion syntax); 1
之间的差值由set /A
计算,结果用于获取@
符号之前的字符串部分(通过子字符串扩展语法); 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). 这种方法的巨大优势在于它甚至可以用于由不止一个字符组成的符号(假设
dir
和findstr
模式相应地进行了调整)。
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): 如果保证在目录名中不能出现字符
^
和%
,则以下代码可以正常工作并且更简单一些( "
也可能是有害字符,但无论如何都禁止使用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
The core function is the substring replacement hack set "LEFT=%LEFT:@=" & rem "%"
in the subroutine :SUB
, which removes the @
sign and everything after. 核心函数是子程序中的子串替换黑客
set "LEFT=%LEFT:@=" & rem "%"
:SUB
,它删除了@
符号及其后的所有内容。 Credits for this method go to Aacini -- see this post . 这种方法的积分转到Aacini - 请看这篇文章 。
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 . 它是Klitos Kyriacou方法的改进版本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.