【发布时间】:2014-12-01 15:53:30
【问题描述】:
我正在寻找一个批处理脚本来(递归地)重命名一个文件夹。 重命名示例: 34354563.randomname_newname.png 到 newname.png
我已经挖掘了 RegEx 以匹配从字符串开头到第一个下划线(其 ^(.*?)_ ),但无法说服 Windows Batch 让我使用 RegEx 进行复制或重命名。
【问题讨论】:
标签: regex windows batch-file
我正在寻找一个批处理脚本来(递归地)重命名一个文件夹。 重命名示例: 34354563.randomname_newname.png 到 newname.png
我已经挖掘了 RegEx 以匹配从字符串开头到第一个下划线(其 ^(.*?)_ ),但无法说服 Windows Batch 让我使用 RegEx 进行复制或重命名。
【问题讨论】:
标签: regex windows batch-file
从命令行提示符 - 没有 regex:
FOR /R %f IN (*.*) DO FOR /F "DELIMS=_ TOKENS=1,*" %m IN ("%~nxf") DO @IF NOT "%n" == "" REN "%f" "%n"
在批处理文件中,双 %:
FOR /R %%f IN (*.*) DO FOR /F "DELIMS=_ TOKENS=1,*" %%m IN ("%%~nxf") DO @IF NOT "%%n" == "" REN "%%f" "%%n"
编辑:一个新的纯批处理解决方案发出以下案例:
批处理(移除 ECHO 以使其正常运行):
FOR /R %%f IN (*.*) DO CALL :UseLast "%%~f" "%%~nf"
GOTO :EOF
:UseLast
FOR /F "DELIMS=_ TOKENS=1,*" %%m IN (%2) DO IF "%%n"=="" (
IF NOT "%~2"=="%~n1" ECHO REN %1 "%~2%~x1"
) ELSE CALL :UseLast %1 "%%n"
GOTO :EOF
【讨论】:
REN "%%f" "%%n"。
test.a_b 这样的名字会变成b。
避免在扩展中使用_:
@ECHO OFF
FOR /F "DELIMS=" %%A IN ('DIR /S /B /A-D *_*.*') DO FOR /F "TOKENS=1*DELIMS=_" %%B IN ("%%~NA") DO IF "%%~C" NEQ "" ECHO REN "%%~A" "%%~C%%~XA"
查看输出,如果看起来不错,删除 ECHO。
【讨论】:
_ 之后的名称。 a_b_c_d.txt 之类的名称将变为 b_c_d.txt,这可能会也可能不会。有关其他选择,请参阅我的答案。
ECHO 轻松预览结果并轻松提交结果的好主意。
REN 之前删除ECHO 时,它才能作为.cmd 工作。
标准的 windows shell 没有正则表达式功能,实际上它非常基础。但是您可以使用 powershell 来执行此操作。
我对 power shell 不是很熟悉,但是另一个问题解释了如何过滤文件:Using powershell to find files that match two seperate regular expressions
【讨论】:
新解决方案
有一个非常简单的解决方案,使用 JREN.BAT,我新的混合 JScript/batch 命令行实用程序,用于通过正则表达式搜索和替换重命名文件和文件夹。
只重命名带有一个下划线的文件:
jren "^[^_]+_([^_]+\.png)$" "$1" /s /i
保留第一个下划线之后的所有内容:
jren "^.*?_" "" /s /fm "*.png"
保留最后一个下划线之后的所有内容:
jren "^.*_" "" /s /fm "*.png"
============================================= ==============
原答案
这可以使用hybrid JScript/batch utility called REPL.BAT 在标准输入上执行正则表达式搜索和替换并将结果写入标准输出来完成。以下所有解决方案都假定 REPL.BAT 位于您的 PATH 中。
我故意将 ECHO 设置为 ON,以便您获得执行的重命名命令的日志。如果您遇到名称冲突,这一点尤其重要:两个不同的起始名称都可能合并为相同的新名称。只有第一次重命名会成功 - 第二次会失败并显示错误消息。
我有三种解决方案,它们的区别仅在于它们如何处理包含超过 1 个_ 字符的名称。
此解决方案只会重命名名称中恰好有一个 _ 的文件(不考虑扩展名)。 a_b_c_d.txt 之类的名称将被忽略。
@echo on&@for /f "tokens=1,2 delims=*" %%A in (
'2^>nul dir /b /s /a-d *_* ^| repl ".*\\[^_\\]*_([^_\\]*\.[^.\\]*)$" "$&*$1" a'
) do ren "%%A" "%%B"
下一个解决方案将保留最后一个 _ 之后的名称。像a_b_c_d.txt 这样的名字会变成d.txt
@echo on&@for /f "tokens=1,2 delims=*" %%A in (
'2^>nul dir /b /s /a-d *_* ^| repl ".*_([^\\_.]*\.[^.\\]*)$" "$&*$1" a'
) do echo ren "%%A" "%%B"
最后一个解决方案将保留第一个 _ 之后的名称。像a_b_c_d.txt 这样的名字会变成b_c_d.txt。这应该给出与 Endoro 答案相同的结果。
@echo on&@for /f "tokens=1,2 delims=*" %%A in (
'2^>nul dir /b /s /a-d *_* ^| repl ".*\\[^\\]*?_([^\\]*\.[^.\\]*)$" "$&*$1" a'
) do echo ren "%%A" "%%B"
【讨论】:
REPL.BAT的优点。但作为一个方便的实用程序,为了提高效率,我更喜欢sed。 1 exe 优于 1 bat > 1 exe > 1 js 和返回。
REPL 工具,而且速度也很快。但是您的正则表达式不适用于没有扩展名的文件。我不知道,这是否是一个真正的问题。
?,另外可能需要在其中一个术语之后使用+,以保证_ 之后至少有一个字符。