0

我有一个脚本,它输出名称以预定义值开头的所有子文件夹。因为我需要它在网络位置上工作,所以我使用 PushD。一切正常,输出符合请求的搜索条件。但是,当前输出显示临时位置上的位置,而不是网络路径上的完整路径。如何修改脚本以显示正确的完整网络位置,而不是临时文件夹上的位置?我可以进行搜索和替换吗?

@echo off
set arg1=%1
set arg2=%2
PushD %arg1% &&(
forfiles /s /m %arg2%* /c "cmd /c if @isdir==TRUE echo @path"
) & PopD

所以当运行 c:\test.bat "\\server\folder" DEMO

将输出...

z:\folder\DEMO_project 1

并不是 ...

\\server\folder\DEMO_project 1

我怎样才能解决这个问题?谢谢...

4

2 回答 2

0

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选项背后的代码,它以具有代码块的方式解析,并被替换为; 查看所有额外插入的解释性注释:forfiles0x22"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 以及它是如何拆分和连接的:

  1. 当前路径D:\是本地路径,并且有一个匹配的子项Sub

    • 提示是D:\\/,回声是rem/.\Sub,所以for /F接收解析:

      D:\\/rem/.\Sub
      
    • for /F将其拆分为三个标记D:\\( %A) 和rem( %B) 和.\Sub( %C);

    • 第二个标记是 just rem,因此只需返回删除了周围引号的绝对路径:

      D:\Sub
      
  2. 当前路径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
      
  3. 当前路径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
      
  4. 当前路径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
      
于 2019-07-17T19:26:34.010 回答
0

正如您已经知道 UNC 路径是\\server\folder,您有什么理由不返回@RelPath吗?

@If "%~2"=="" Exit /B 
@PushD "%~1" 2>NUL&&(
    ForFiles /M "%~2*" /S /C "Cmd /C If @IsDir==TRUE Echo @RelPath"
)&PopD&Pause

在这种情况下,返回的输出看起来更像这样.\folder\DEMO_project 1


如果您确实需要添加已知的 UNC,则可以使用另一轮解析来用已知字符串替换前导句点:

@If "%~2"=="" Exit /B
@PushD "%~1" 2>NUL&&(
    ForFiles /M "%~2*" /S /C "Cmd /Q/C If @IsDir==TRUE For /F \"Tokens=*Delims=.\" %%A In (@RelPath)Do Echo %~1%%~A"
)&PopD&Pause

这个例子返回的输出有点像这样,\\server\folder\folder\DEMO_project 1


请注意,我已经发布了完整示例来完全替换您发布的代码,它们不需要任何修改!

于 2019-07-17T14:26:49.043 回答