在 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 了解有关命令 SETLOCALENDLOCAL 的详细信息。

演示代码并没有真正运行命令REN,它只是输出如何在删除命令ECHO时执行REN。 p>

【讨论】:

非常感谢。通过您的示例,我可以创建完整的批处理文件。非常感谢。我把我的批次的这个例子留给你看,但我不明白你对这个脚本的了解。 filebin.net/vh355pwy1uau3xpf/…

以上是关于在 CMD 中使用 enabledelayedexpansion 时如何获取具有特殊字符的子字符串?的主要内容,如果未能解决你的问题,请参考以下文章

在 CMD 中使用环境变量

如何在cmd中使用输入

如何使用 CreateProcess 在 cmd 中执行命令?

在 prepareStatement 中使用 COALESCE 来“插入”cmd

cmd中怎么调用python脚本?

如何使用c#在cmd中运行命令[重复]