该prompt
命令可以显示网络路径,以防驱动器指向网络路径,但不幸的是SPACE返回了一个尾随。无论如何,这可以使用如下:
@echo off
pushd "%~1" && (
forfiles /S /M "%~2*" /C "cmd /Q /C if @isdir==TRUE for /F 0x22tokens=1-3 delims=/0x22 %%A in ('prompt $P\/$M^& for %%z in ^(@relpath^) do rem/%%~z') do if 0x22%%B0x22==0x22rem0x22 (for %%z in (@path) do echo(%%~z) else set 0x22SH=%%B/.\%%~pA rem/%%C0x22 & cmd /V /C echo(!SH: rem/.\=!"
popd
)
为了解释命令/C
选项背后的代码,它以具有代码块的方式解析,并被替换为; 查看所有额外插入的解释性注释:forfiles
0x22
"
rem
rem // Execute the following code only when the current item is a directory:
if @isdir==TRUE (
rem // Capture the following command echo string:
for /F "tokens=1-3 delims=/" %%A in ('
rem/ Set the prompt string, then use a `for` loop that iterates once, ^^
rem/ executes `rem` with the relative path of the current item and ^^
rem/ just echos this with the prompt string preceded: ^& ^^
prompt $P\/$M^& for %%z in ^(@relpath^) do rem/%%~z
') do (
rem // The second token is just `rem` in case we have a local path:
if "%%B"=="rem" (
rem /* Simply echo the full path of the local path, but with the surrounding
rem quotation marks removed by a `for` loop and the `~` modifier: */
for %%z in (@path) do echo(%%~z
) else (
rem /* For a network path, we need to build the absolute UNC path by joining
rem the captured network path from the echo string, the path relative to
rem the drive mapped by `pushd` and the relative path from `forfiles`;
rem // since the echo string also contains the echoed command `rem` itself,
rem let us smartly assemble a string that requires only one replacement: */
set "SH=%%B/.\%%~pA rem/%%C"
rem /* Echo the build absolute network path with two removals of ` rem/.\`;
rem enable delayed expansion at this point to avoid losses of `!`: */
cmd /V /C echo(!SH: rem/.\=!
)
)
)
延迟扩展SH
对于在同一行代码中修改和收集变量是必要的。
然后使用子字符串替换来删除来自回显命令的伪影rem
。
为了详细解释代码是如何工作的,让我们假设一些示例情况,并查看带有前面提示字符串的命令 echo 以及它是如何拆分和连接的:
当前路径D:\
是本地路径,并且有一个匹配的子项Sub
:
提示是D:\\/
,回声是rem/.\Sub
,所以for /F
接收解析:
D:\\/rem/.\Sub
for /F
将其拆分为三个标记D:\\
( %A
) 和rem
( %B
) 和.\Sub
( %C
);
第二个标记是 just rem
,因此只需返回删除了周围引号的绝对路径:
D:\Sub
当前路径D:\Data\Test
是本地路径,并且有一个匹配的子项Sub
:
提示是D:\Data\Test\/
,回声是rem/.\Sub
,所以for /F
接收解析:
D:\Data\Test\/rem/.\Sub
for /F
将其拆分为三个标记D:\Data\Test\
( %A
) 和rem
( %B
) 和.\Sub
( %C
);
第二个标记是 just rem
,因此只需返回删除了周围引号的绝对路径:
D:\Data\Test\Sub
当前路径Z:\
是驱动器Z:
指向远程位置的网络路径\\SERVER\Share
,并且有一个匹配的子项Sub
:
提示是Z:\\/\\SERVER\Share
+ SPACE,回声是rem/.\Sub
,所以for /F
接收解析:
Z:\\/\\SERVER\Share rem/.\Sub
for /F
将其拆分为三个标记Z:\\
( %A
) 和\\SERVER\Share rem
( %B
) 和.\Sub
( %C
);
第二个标记不仅仅是rem
,所以 append /.\
,然后是Z:
删除驱动器的第一个标记(因此\
used~p
修饰符解析\\
为\
),然后是SPACE+ rem/
,然后是第三个标记,所以我们得到这个字符串:
\\SERVER\Share rem/.\\ rem/.\Sub
删除子字符串的两个实例后SPACE+rem/.\
我们终于得到:
\\SERVER\Share\Sub
当前路径Z:\Test
是驱动器Z:
指向远程位置的网络路径\\SERVER\Share
,并且有一个匹配的子项Sub
:
提示是Z:\Test\/\\SERVER\Share
+ SPACE,回声是rem/.\Sub
,所以for /F
接收解析:
Z:\Test\/\\SERVER\Share rem/.\Sub
for /F
将其拆分为三个标记Z:\Test\
( %A
) 和\\SERVER\Share rem
( %B
) 和.\Sub
( %C
);
第二个标记不仅仅是rem
,所以 append ,然后是删除/.\
驱动器的第一个标记(因此),然后是+ ,然后是第三个标记,所以我们得到这个字符串:Z:
\Test\
SPACErem/
\\SERVER\Share rem/.\\Test\ rem/.\Sub
删除子字符串的两个实例后SPACE+rem/.\
我们终于得到:
\\SERVER\Share\Test\Sub