windows - 当字符串中有括号时如何用子字符串替换字符串

标签 windows batch-file cmd

过去两天我一直在绞尽脑汁,试图编写一个代码来读取文件夹结构并删除列表的基本路径。

到目前为止我所拥有的是:

@ECHO OFF
CLS
SETLOCAL EnableExtensions EnableDelayedExpansion

SET "StartTime=%TIME: =0%"
SET "Folder=%~1"
IF "%Folder:~-1%"=="\" SET "Folder=%Folder:~0,-1%"
FOR %%G IN ("%Folder%") DO SET "Archive=%%~nxG"
ECHO Processing %Folder%...
ECHO.
PUSHD "%Folder%"
FOR /F "DELIMS=" %%G IN ('DIR /A:-D /B /O:N /S') DO (
   SET "FullPath=%%G"
   ECHO !FullPath:%Folder%\=! >> "%Archive%.$$$"
)
pause
endlocal
goto :eof

只要目录没有 ( 或 ) (例如 C:\Program Files (x86)\AMD),此操作就可以正常工作,然后向我抛出一条错误消息并停止。

找不到任何解决方案来绕过此限制。任何意见都将受到高度赞赏。 谢谢!

最佳答案

来自 Mofi 的精彩解释和解决方案

这里有一个更短、更直接的方法来实现可靠的解决方案,该解决方案仍然依赖于 Mofi 使用 FOR /F 的基本技术。 tokensdelims删除根路径。

我的代码不允许指定路径,在这种情况下它默认为当前目录。用于规范化、验证和从根路径中提取所需值的代码已大大简化。

我还使用了一种完全不同的方法来计算根路径中的 token 数量。我用换行符替换 \字符,然后用 FIND /C 计算行数当我回显该值时。这有点棘手,但它非常高效并且无需求助于 GOTO 即可工作。循环。

如果没有找到文件,我也会保留错误消息,并且不会删除生成的空文件。

@echo off
setlocal disableDelayedExpansion

::==== Get normalized values for supplied path in %1
::==== Default to current directory if not specified
for %%F in ("%~f1.") do (  %=== The trailing dot allows paths with/without trailing \ to work %
  set "folder=%%~fF"   ==== The normalized path for the root folder
  set "archive=%%~nxF" ==== The base name of the output file
  set "att=-%%~aF"     ==== List of attributes for the root folder
)

::==== Validate path by checking for d in attributes
if %att:d=% == %att% (
  >&2 echo Supplied path is invalid or not a folder
  exit /b 1
)

::==== Special handling if drive root
if not defined archive (
  set "archive=drive %folder:~0,1% root"
  set cnt=1
  goto start
)

::==== Normal processing for all other paths
setlocal enableDelayedExpansion
for %%L in (^"^
%==== Puts quoted newline in FOR variable L %
^") do set "folder2=!folder:\=%%~L!"   ==== Substitutes newline for all \ in folder
::==== Count the number of tokens (lines) in folder2
setlocal disableDelayedExpansion
for /f %%N in ('"(cmd /v:on /c echo !folder2!)|find /c /v """') do set cnt=%%N

:start  ==== Finally get the sorted list of files without root path
>"%archive%.$$$" (
  for /f "delims=\ tokens=%cnt%*" %%A in ('dir "%folder%" /a:-d /b /o:n /s') do echo %%B
)

代码非常简洁,没有注释和多余的空行

@echo off
setlocal disableDelayedExpansion
for %%F in ("%~f1.") do (
  set "folder=%%~fF"
  set "archive=%%~nxF"
  set "att=-%%~aF"
)
if %att:d=% == %att% (
  >&2 echo Supplied path is invalid or not a folder
  exit /b 1
)
if not defined archive (
  set "archive=drive %folder:~0,1% root"
  set cnt=1
  goto start
)
setlocal enableDelayedExpansion
for %%L in (^"^

^") do set "folder2=!folder:\=%%~L!"
setlocal disableDelayedExpansion
for /f %%N in ('"(cmd /v:on /c echo !folder2!)|find /c /v """') do set cnt=%%N
:start
>"%archive%.$$$" (
  for /f "delims=\ tokens=%cnt%*" %%A in ('dir "%folder%" /a:-d /b /o:n /s') do echo %%B
)

更新响应 Mofi's comment

我原来的答案没有考虑输入中使用通配符的可能性。可以通过在初始 SETLOCAL 之后添加以下内容来排除通配符

for /f "delims=*?<> tokens=2" %%A in (".%~1.") do (
  >&2 echo Wildcards * ? ^< and ^> not supported
  exit /b 1
)

请注意"<"">"poorly documented wildcards (仅当它们在路径中被引用时)!

但是莫菲描述了一种我以前从未见过的有趣行为。起初我不明白怎么C:\test\*正在产生C:\ .

这就是 %~f1 的结果看到.目录条目作为测试文件夹中第一个列出的文件/文件夹,然后当我的代码附加自己的点时,它变成 C:\test\.. ,当然标准化为 C:\ .

有一段时间我认为当路径节点只是通配符时会进行特殊处理,但我 posted the behavior on DosTips一位回复者让我想起了 ...除驱动器根目录外的所有目录条目。

关于windows - 当字符串中有括号时如何用子字符串替换字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61436029/

相关文章:

windows - 为什么 CMD 转义字符会变魔术而不是转义新行

c - strstr 在内核空间中无法正常工作

windows - 如果我在 Windows 中复制并覆盖目标文件,创建/修改日期不会改变

windows - UNIX shell 脚本在 Windows 中的等效项是什么?

windows - 为什么从 Windows 批处理文件启动的 ffmpeg.exe 不等待用户输入就立即关闭?

windows - "%~dp0"和 ".\"之间的区别?

windows - 为什么 D 不允许嵌套函数重载?

c++ - 如何获取按键的扫描码?

windows - 我可以防止一个批处理文件同时被 1 个以上的用户执行吗

batch-file - 我可以创建 .bat 文件来自动在 ODBC 数据源管理器中添加数据源吗?