是否可以检测是否使用CALL命令启动批处理文件?

时间:2015-11-26 13:29:23

标签: batch-file

问题在于CALL command doubles插入符号^并制作了双percentage a single one。在hybrid文件中,这可能是一个很大的问题。如果没有用另一个蝙蝠的CALL执行蝙蝠并且你想警告用户。

%cmdcmdline%(尽管如果文件是直接从提示中执行的话可以使用)和(goto)>nul(最终可以与this一起使用)我认为没用的技术这里。

我仍然在考虑这个问题,但是如果有人提供优雅的解决方案会很棒。

修改即可。一种可能的方法是检测batch recursion level虽然需要一种可靠的方法来检查这个配置条目(我不知道它是如何计算的)。

5 个答案:

答案 0 :(得分:4)

我理解你的问题,你想要一个方法,允许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!

答案 1 :(得分:4)

如果我能理解你的问题:你想要一个方法,允许批处理脚本确定它是否是通过另一个批处理脚本的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的内容如下( copy& paste 部分包含在内):

@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)技术相结合可以提供帮助吗?

答案 2 :(得分:3)

可以使用一些讨厌的技巧来完成,因此不是一个完美的解决方案
我计算了获取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 

答案 3 :(得分:3)

Jeb's answer一样,如果当前批处理文件已被调用或已从被调用的批处理文件直接调用,则无法区分。此代码只检测执行上下文是否为批处理文件(某处有@Bean SecurityConfiguration security() { return new SecurityConfiguration( "test-app-client-id", "test-app-client-secret", "test-app-realm", "test-app", "YOUR_API_AUTH_TOKEN", ApiKeyVehicle.HEADER, "X-AUTH-TOKEN", "," /*scope separator*/); } 到达此点)或命令行(没有任何call或初始上下文是命令行)。不一样,但也许有人可以从中获得更好的方法。

在杰布的评论之后

编辑。我虽然call可能更有问题,但它不是,所以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

答案 4 :(得分:2)

低技术解决方案,只需设置并检查环境变量即可。像这样:

caller.cmd:

SET calling=1
CALL called.cmd
SET calling=

called.cmd

IF [%calling%]==[1] SET PATH=%PATH%;.