批处理脚本中的函数返回值传递给另一个函数

3
这可能是 SO、dostips 和 ss64 中的几个问题的重复。我所做的研究指出,需要在函数中注意 _scope_,但我的解决方案简单直接,但问题仍然存在。
  1. SETLOCALENDLOCAL 的真正含义是什么
  2. context 在批处理脚本中如何工作,例如:(goto) 2>nul
  3. (goto) 包含在大括号中的原因(在 dostips 中有解释)

以下是我编写的代码,用于将文件从一个位置复制到另一个位置。

  • 研究批处理脚本的 scopecontext
  • 代码重用
    @echo off
    setlocal EnableDelayedExpansion
    goto :main
:main setlocal set _app=test set _base=C:/wamp64/www set _destination=!_base!/test set _source=%~dp0%/build set /A _flag=0
echo ********************************************* echo 部署在 %~1 模式下: %TIME% echo 部署路径: !^_destination! echo *********************************************
call :check !_base!, !_app!, _flag if !_flag!==0 ( call :create !_base!, !_app! ) xcopy "!_source!" "!_destination!" /D /C exit /b 0 endlocal
:setbase echo ::::: 设置基础目录 ::::: chdir /D C:
rem 为应用程序设置基本目录 => %1 chdir %~1 exit /b 0
:check echo ::::: 检查本地Web服务器目标 ::::: call :setbase %~1
set %~3= dir /p|find /C "%~2" exit /b 0
:create echo ::::: 创建应用程序文件夹 :::::
rem 将基础设置为创建应用程序文件夹 %1 call :setbase %~1 mkdir %~2 exit /b 0
endlocal
这是我启动deploy.bat时得到的输出:
*********************************************
   以生产模式部署: 19:28:53.13
       部署路径:C:/wamp64/www/test
*********************************************
::::: 检查本地 Web 服务器目标 :::::
::::: 设置基础 :::::
0
::::: 创建应用程序文件夹 :::::
::::: 设置基础 :::::
子目录或文件 test 已经存在。
看起来If !_flag!==0,它检查服务器根目录中是否存在应用程序文件夹,但根本不起作用。当我学习如何将参数传递给其他函数时,我认为它像引用一样传递pointer,但它似乎与scope紧密相关。那么在代码中发生了什么?

1
:check 中,当你设置 _flag 时,实际上并没有运行命令,而是将该变量设置为字面字符串。使用 for /F 将命令输出存储到变量中。 - SomethingDark
1
请注意,它是%~dp0,而不是%~dp0% - double-beep
1个回答

3

检查文件/目录是否存在

您正在使用的代码来验证目录是否存在:

set %~3= dir /p|find /C "%~2"

我认为这不是你想要的结果。 SET /P通常用于将命令输出导入环境变量中。(但是,您正在将/P传递给dir,这会分页输出,可能不是您想要的。)但是,您的命令不会这样做。我猜测这个命令所完成的是将变量设置为(字面上的)“ dir /p”,然后将其通过find-count进行管道处理。然而,find.exe /C的结果从未返回到环境变量中。输出行“0”是通过find.exe /C将(无)内容进行管道处理的结果。 我提出了一个更简单的存在性测试:
IF EXIST "%~2" (SET /A %~3=1) ELSE (SET /A %~3=0)

这个测试在我的Win10机器上成功了。
我看到IF EXIST的工作方式有些差异。如果你不想使用它,你可以用FOR循环来实现。
FOR /F "tokens=*" %%e IN ('DIR /B') DO IF "%%~e"=="%~2" SET /A %~3=1

如果您想在FOR命令中使用管道符号,请对其进行转义处理。

FOR /F "tokens=*" %%e IN ('DIR /B ^| find /C "%~2"') DO SET /A %~3=%%~e

这三种方法都对我有效。

SETLOCAL

我认为除了内置的帮助 (SETLOCAL /?),cmd语法没有官方参考指南。

我的经验是,它将所有的环境变量和工作目录推送到一个“堆栈”上,相应的 ENDLOCALEXIT (尽管在脚本中,你几乎总是要使用 EXIT /B) 将从该“堆栈”中弹出环境。实际上,这意味着你在 SETLOCAL 中做的环境变量/当前工作目录更改只是临时的。


虽然在脚本中,通常都要使用 EXIT /B。这是因为如果函数结尾没有定义 exist /b,则通常的执行流程将继续往下执行,最终可能会导致递归达到最大深度。 - LasithaMD
这个技巧 IF EXIST "%~2" (SET /A %~3=1) ELSE (SET /A %~3=0) 解决了问题。 - LasithaMD

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