file.bat
的文件能够确定它是否是通过其他批处理文件中的call
命令调用的,并且需要在批处理文件中插入额外的检查代码来实现这一点,对吗?file.bat
中未定义此类变量时,它就不是通过call
进行调用的:set "callFlag=1"
call file.bat
在file.bat文件中:
if not defined callFlag echo Warning, I was not executed via CALL command!
这可以通过一些“恶劣”的技巧来完成,因此这并不是一个完美的解决方案。
我计算出需要多少次调用才能得到一个stackoverflow,然后将该值与错误输出的值进行比较。
但是需要启动第二个cmd.exe进程,因为stackoverflow会杀死第一个批处理实例。
@echo off
setlocal EnableDelayedExpansion
set "_fileCheck=%~0"
if "!_fileCheck:~-4!"==".bAt" goto :child
del stackoverflow.log
start "" /b "%~dpn0.bAt" AllParameters
set count=0
(call :recusion & echo NEVER) 1> stackoverflow.log 2>&1
echo #* NEVER
exit /b
:recusion
set /a count+=1
echo +%count%
call :recusion
:child
ping -n 2 localhost 2>&1 > nul
:loop
(
< stackoverflow.log (
rem dummy
) || goto :loop
) 2>nul
:X
for /F "tokens=1,2 delims=,=" %%L in ('type stackoverflow.log') do (
set "line=%%L"
set "firstChar=!line:~0,1!"
if "!firstChar!"=="+" (
set /a maxCount=!line!
) ELSE if "!firstChar!" NEQ "*" (
set /a overflow=%%M
)
)
if !maxCount! EQU !overflow! (
echo Direct started
) ELSE (
echo CALL started
)
exit
if exist .. goto :loop
жҲ–еҸҜиғҪдҪҝз”Ёdbenhamзҡ„жҠҖе·§д№ӢдёҖжқҘе®ҢжҲҗгҖӮ - jebcall
命令以达到当前批处理文件,而不能检测到调用当前批处理文件的 call
命令。如果 a.bat
调用(即使用 call
命令)b.bat
,而 b.bat
直接调用(不使用 call
)你的批处理文件,则此方法将返回错误的正面 call
命令使用情况。 - MC ND如果我理解您的问题正确:您想要一种方法,使批处理脚本能够确定它是否是通过另一个批处理脚本的call
命令调用的。下面的33939966test.bat
脚本展示了可能的解决方案:使用强制性参数"^%%%%"
进行使用,如下:
@ECHO OFF >NUL
if "%~1" == "" goto :USAGE
if "%~1" == "^^%%" echo call from another script %* & goto :GOOD
if "%~1" == "^%%%%" echo from another script %* & goto :USAGE
if "%~1" == "^^%%%%%%%%" echo call from command line %* & goto :USAGE
if "%~1" == "^%%%%%%%%" echo from command line %* & goto :USAGE
echo(wrong 1st parameter %%*=%*
goto :USAGE
:GOOD
echo(
rem echo original %%*=%*
shift /1
rem echo shifted %%*=%*
:: Note that `shift` does not affect %*
:::::::::::::::::::::::::::::::::::::::
:: Useful code begins here
goto :eof
:USAGE
echo USAGE: CALL %~nx0 "^%%%%%%%%" [parameters]
echo(
rem the 1st parameter must be:
rem "CARET followed by four PERCENT SIGNS" including all " DOUBLE QUOTES
goto :eof
命令行输出:
==> rem cmd copy&paste start
==> ECHO OFF >NUL
33939966test.bat "C&D pay 21 % VAT" "^=caret" %OS% %%OS%%
wrong 1st parameter %*="C&D pay 21 % VAT" "^=caret" Windows_NT %Windows_NT%
USAGE: CALL 33939966test.bat "^%%%%" [parameters]
call 33939966test.bat "^%%%%" "C&D pay 21 % VAT" "^=caret" %OS% %%OS%%
call from command line "^^%%%%" "C&D pay 21 % VAT" "^^=caret" Windows_NT %Windows_NT%
USAGE: CALL 33939966test.bat "^%%%%" [parameters]
33939966test.bat "^%%%%" "C&D pay 21 % VAT" "^=caret" %OS% %%OS%%
from command line "^%%%%" "C&D pay 21 % VAT" "^=caret" Windows_NT %Windows_NT%
USAGE: CALL 33939966test.bat "^%%%%" [parameters]
ECHO ON >NUL
==> rem cmd copy&paste end
来自调用方的输出:
==> 33939966myCaller.bat
==> call 33939966test.bat "C&D pay 21 %% VAT" "^=caret" Windows_NT %OS%
wrong 1st parameter %*="C&D pay 21 % VAT" "^^=caret" Windows_NT Windows_NT
USAGE: CALL 33939966test.bat "^%%%%" [parameters]
==> call 33939966test.bat "^%%" "C&D pay 21 %% VAT" "^=caret" Windows_NT %OS%
call from another script "^^%" "C&D pay 21 % VAT" "^^=caret" Windows_NT Windows_NT
==> 33939966test.bat "^%%" "C&D pay 21 % VAT" "^=caret" Windows_NT %OS%
from another script "^%%" "C&D pay 21 % VAT" "^=caret" Windows_NT %OS%
USAGE: CALL 33939966test.bat "^%%%%" [parameters]
在此,33939966myCaller.bat
的读取方式如下(包括 复制&粘贴 部分):
@ECHO ON
call 33939966test.bat "C&D pay 21 %%%% VAT" "^=caret" %OS% %%OS%%
@ECHO ON
call 33939966test.bat "^%%%%" "C&D pay 21 %%%% VAT" "^=caret" %OS% %%OS%%
@ECHO ON
33939966test.bat "^%%%%" "C&D pay 21 %% VAT" "^=caret" %OS% %%OS%%
@ECHO OFF
goto :eof
rem cmd copy&paste start
ECHO OFF >NUL
33939966test.bat "C&D pay 21 % VAT" "^=caret" %OS% %%OS%%
call 33939966test.bat "^%%%%" "C&D pay 21 % VAT" "^=caret" %OS% %%OS%%
33939966test.bat "^%%%%" "C&D pay 21 % VAT" "^=caret" %OS% %%OS%%
ECHO ON >NUL
rem cmd copy&paste end
==> 33939966test.bat "^^%" "C&D pay 21 % VAT" "^=caret" %OS% %%OS%%
call from another script "^^%" "C&D pay 21 % VAT" "^=caret" Windows_NT %Windows_NT%
(goto)
技术可以有帮助?call
来到达此点)或命令行(没有call
或初始上下文为命令行)。虽然不同,但也许有人可以从中得出更好的方法。
Jeb的评论之后进行了编辑。我认为echo
可能会更有问题,但事实并非如此,所以(goto)
方法显然是更好的选择。
@echo off
rem Check if this is the initial invocation or we have already determined
rem how the batch file was started
rem If already tested save method, remove test variable and goto main
if defined __callTest__ (
set "startMethod=%__callTest__%"
set "__callTest__="
goto :main
)
rem Initial invocation - Test routine
rem Cancel current batch context and check if the new context is
rem - batch (there was a call somewhere)
rem - command line (no call)
rem Once the invocation method is determined, restart the current batch
setlocal enableextensions disabledelayedexpansion
call :getCurrentFile _f0
(
rem Cancel context
2>nul (goto)
rem The context cancel operation interferes with echo logic. Restore
echo on
rem We try to read a non existing variable and see if we could.
rem - In command line context, the reading of a non existing variable
rem returns the name of the variable, setting our test var
rem - In batch context, reading a non existing variable does not
rem return anything, and the test variable is undefined
call set "__callTest__=%%{[%random%""%random%]}%%"
if defined __callTest__ (
set "__callTest__=direct"
"%_f0%" %*
) else (
set "__callTest__=call"
call "%_f0%" %*
)
)
:getCurrentFile returnVar
set "%~1=%~f0"
goto :eof
rem Main batch code
:main
setlocal enableextensions disabledelayedexpansion
echo Method invocation is [ %startMethod% ]
goto :eof
%*
。.test.
调用,你可以用(goto) 2> nul
替换"%_f0%" .test.
- jeb.test.
是因为(至少在我的环境中)这样更干净(是的,也更慢)。 (goto)
保留了 echo off
的状态,稍后需要重新启用它(至少在命令行中工作时),而直接批处理调用不会发生这种情况。 - MC NDecho
,但实际上并不需要。(goto)
胜出,答案已更新。谢谢。 - MC NDSET calling=1
CALL called.cmd
SET calling=
called.cmd
IF [%calling%]==[1] SET PATH=%PATH%;.
(goto)>nul
技巧对于CALL
和直接启动都会产生相同的结果。cmdcmdline
也会产生相同的结果。(goto)
只在从命令行本身使用call
时显示相同的结果,但不是在从另一个批处理文件中使用时。因此,MC ND 的解决方案似乎几乎完美。链接 - jeb