使用批处理延迟扩展时,路径中的特殊字符(感叹号!,脱字符^等)出现问题。

5
我已经搜索过了,但无法找到任何可以使我的脚本正确处理特殊字符(例如!;^)在文件路径或文件名中的内容。
我的脚本确实可以工作,但仅当上述字符不在任何扫描的文件夹或文件名中时。如果任何文件夹或文件具有这些字符,则脚本会崩溃。我需要帮助解决如何使我的脚本能够处理路径或文件名中的特殊字符(如上所述)。以下是我的脚本:
set srcdir=%~dp0%src

set desdir=%~dp0%des

setlocal EnableDelayedExpansion
for /r "%srcdir%" %%f in ("*.txt") do (
    set "subdir=%%~f"
    set "subdir=!subdir:%srcdir%=%desdir%!"
    echo !subdir!
    pause
)
endlocal

感谢所有的支持和帮助!

2个回答

3
  1. 将所有路径放在""之间。
  2. 始终使用语法set "VAR=Value"
  3. 切换延迟扩展:当扩展%%~F时,禁用它;之后启用它。

这是修复过的代码:

setlocal DisableDelayedExpansion

set "srcdir=%~dp0src"
set "desdir=%~dp0des"

for /R "%srcdir%" %%F in ("*.txt") do (
    set "subdir=%%~F"
    setlocal EnableDelayedExpansion
    set "subdir=!subdir:%srcdir%=%desdir%!"
    echo(!subdir!
    pause
    endlocal
)
endlocal

只要批处理文件所在的目录不包含感叹号,这个方法就有效。如果包含,请让我知道……


修正

使用变量进行查找和替换的子字符串替换一般来说并不安全,因为它无法处理所有字符。

想象一下你有以下内容:

echo(!VAR:%SEARCH%=%REPLACE%!

这意味着要替换每个不区分大小写的%SEARCH%%REPLACE%

但是,如果%SEARCH%包含一个=,行为会发生改变:例如,%SEARCH%a=b%REPLACE%cd,则立即展开的版本是!VAR:a=b=cd!,因此每个a都将被替换为b=cd

%SEARCH%中的前导*会改变行为:将所有内容替换为%REPLACE%,直到包括%SEARCH%在内的剩余部分。(星号当然不能出现在路径中。)

%SEARCH%中的前导~将行为从子字符串替换更改为子字符串扩展,即根据字符位置和长度扩展字符串部分;如果违反语法,则会按原样返回非扩展字符串!VAR:~a=b!,假设~ab分别是搜索和替换字符串。

最后,如果%SEARCH%和/或replace包含一个!,则该字符将被视为延迟扩展的关闭!,因此!VAR:a!=b!被视为!VAR:a!,这是无效的语法,将保持原样。


哇,我知道我很接近,但直到看到这个,所有的东西才一下子变得清晰了。非常感谢! - Nathan Klayko

3
当启用延迟扩展并且您正在设置变量时,感叹号将被覆盖。您可以通过等待延迟扩展直到检索变量值来避免这种情况。有时这需要一些技巧才能使它正常工作。在这种情况下,最简单的方法可能是禁用延迟扩展并使用call来延迟扩展。
@echo off
setlocal

set "srcdir=%~dp0%src"
set "desdir=%~dp0%des"

for /r "%srcdir%" %%f in ("*.txt") do (
    set "subdir=%%~f"

    rem // use call to avoid delayed expansion and preserve exclamation marks
    call set "subdir=%%subdir:%srcdir%=%desdir%%%"

    rem // use set /p rather than echo to exploit quotation marks and preserve carets
    call set /P "=%%subdir%%"<NUL & echo;
    pause
)

如果你更喜欢延迟执行,我推荐使用一个技巧来在一行中切换延迟执行,就是使用类似这样的 for 循环:

@echo off
setlocal

set "srcdir=%~dp0%src"
set "desdir=%~dp0%des"

for /r "%srcdir%" %%f in ("*.txt") do (
    set "subdir=%%~f"
    setlocal enabledelayedexpansion
    for %%I in ("!subdir:%srcdir%=%desdir%!") do endlocal & set "subdir=%%~I" & echo(%%~I
    pause
)

非常感谢您的回复。我更喜欢关闭延迟扩展,所以最终使用了您第一个答案中的调用技术。再次感谢您的帮助! :) - Nathan Klayko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接