过去两天我一直在绞尽脑汁,试图编写一个代码来读取文件夹结构并删除列表的基本路径。
到目前为止我所拥有的是:
@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
的基本技术。 tokens
和delims
删除根路径。
我的代码不允许指定路径,在这种情况下它默认为当前目录。用于规范化、验证和从根路径中提取所需值的代码已大大简化。
我还使用了一种完全不同的方法来计算根路径中的 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/