在 CMD 中使用 enabledelayedexpansion 时如何获取具有特殊字符的子字符串?
Posted
技术标签:
【中文标题】在 CMD 中使用 enabledelayedexpansion 时如何获取具有特殊字符的子字符串?【英文标题】:How to get a substring with a special character when use enabledelayedexpansion in CMD? 【发布时间】:2020-07-11 08:37:54 【问题描述】:我想使用 cmd 重命名一个或多个文件。但是很多这些文件都有一个特殊字符。 示例:
DCIM_!01.jpeg
DCIM_&01.jpeg
DCIM_=01.jpeg
通常,我们可以使用这个值“^”将一个特殊的字符串设置为简单的文本。但是当设置 enabledelayedexpansion 时,字符串不是可设置的
set /p mystring=!
用户定义字符串值:!、&、= 等...
文件名由其他变量“FOR”定义以在文件夹中搜索
所以字符串“文件”的值为“DCIM_!01.jpeg”
更改文件名的命令:
setlocal enabledelayedexpansion
set new_filename=!file:^%mystring%=0!
echo !new_filename!
提示的结果是:
:=0
file:=0
DCIM_!01.jpeg
DCIM_01.jpeg
我想重写“!”到“0”:
DCIM_001.jpeg
当我不使用特殊字符串时,该命令对我有效
【问题讨论】:
有什么理由不只是disabledelayedexpansion
?这样一来,ren "DCIM_%mystring:~0,1%01.jpeg" "DCIM_001.jpeg"
即使使用像 &
这样的字符也是非常安全的。 (无法处理"
,但文件名无论如何不能包含引号)
【参考方案1】:
这是一个快速演示代码:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "TempDir=%TEMP%\%~n0"
if exist "%TempDir%\" goto CreateFiles
md "%TempDir%" && goto CreateFiles
echo Failed to create temporary directory:
echo/
echo "%TempDir%"
echo/
pause
rem The command endlocal is executed implicit by cmd.
exit /B
:CreateFiles
pushd "%TempDir%"
echo DCIM_!01.jpeg>"%TempDir%\DCIM_!01.jpeg"
echo DCIM_^&02.jpeg>"%TempDir%\DCIM_&02.jpeg"
echo DCIM_=03.jpeg>"%TempDir%\DCIM_=03.jpeg"
echo DCIM_%%04.jpeg>"%TempDir%\DCIM_%%04.jpeg"
echo DCIM_)05.jpeg>"%TempDir%\DCIM_)05.jpeg"
:UserPrompt
set "MyString="
set /P "SearchString=String to replace: "
rem Has the user not entered a string?
if not defined SearchString goto UserPrompt
rem Remove all double quotes.
set "SearchString=%SearchString:"=%"
rem Is there no search string left?
if not defined SearchString goto UserPrompt
rem Replace all exclamation marks by vertical bars.
set "SearchString=%SearchString:!=|%"
echo/
for /F "eol=| delims=" %%I in ('dir "*.jpeg" /A-D /B 2^>nul') do (
set "RealName=%%I"
set "FileName=%%I"
rem Replace in file name all exclamation marks by vertical bars.
call set "FileName=%%FileName:!=|%%"
setlocal EnableDelayedExpansion
set "NewName=!FileName:%SearchString%=0!"
if not "!NewName!" == "!FileName!" echo ren "!RealName!" "!NewName!"
endlocal
)
echo/
%SystemRoot%\System32\choice.exe /C NY /N /M "Run once more (Y/N):"
if errorlevel 2 goto UserPrompt
popd
rd /Q /S "%TempDir%"
endlocal
您可以看到演示代码不适用于包含=
的搜索字符串。必须有用于替换等号的特殊代码,或者使用不同的脚本解释器,如 PowerShell。
另见:How to replace “=” (equal signs) and a string variable?
感叹号的解决方案是将搜索字符串中的每个!
替换为|
,并在启用延迟环境变量扩展之前对当前文件名执行相同操作。如 Microsoft 在文档页面 Naming Files, Paths, and Namespaces 中所述,文件名不能包含竖线。因此,在使用启用的delayed expansion 进行字符串替换之前,将文件名中的所有!
替换为|
是安全的。
在 FOR 循环中将!
替换为|
必须通过将环境变量FileName
引用为%%
来完成。原因是命令行
call set "FileName=%%FileName:!=|%%"
在执行命令FOR to
之前由cmd.exe
处理
call set "FileName=%FileName:!=|%"
命令CALL用于在循环的每次迭代中强制cmd.exe
对该命令行进行第二次解析和处理,以真正对分配给环境变量的当前字符串值进行字符替换FileName
.
另见:
Variables are not behaving as expected How does the Windows Command Interpreter (CMD.EXE) parse scripts?然后可以启用延迟扩展对已经稍微修改过的文件名进行字符串替换,并对真正被字符串替换的文件名运行命令REN 用当前文件和新文件的真实名称替换姓名。阅读 this answer 了解有关命令 SETLOCAL 和 ENDLOCAL 的详细信息。
演示代码并没有真正运行命令REN,它只是输出如何在删除命令ECHO时执行REN。 p>
【讨论】:
非常感谢。通过您的示例,我可以创建完整的批处理文件。非常感谢。我把我的批次的这个例子留给你看,但我不明白你对这个脚本的了解。 filebin.net/vh355pwy1uau3xpf/…以上是关于在 CMD 中使用 enabledelayedexpansion 时如何获取具有特殊字符的子字符串?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 CreateProcess 在 cmd 中执行命令?