Batch file 是否可以检测批处理文件是使用CALL命令启动的,还是不使用CALL命令启动的?

Batch file 是否可以检测批处理文件是使用CALL命令启动的,还是不使用CALL命令启动的?,batch-file,Batch File,问题是调用插入符号^并使其加倍。在文件中,这可能是一个大问题。或者,如果一个bat没有使用另一个bat的调用执行,并且您想要警告用户 %cmdline%(尽管如此,如果直接从提示符执行文件,也可以使用此方法)和(最终可以与此一起使用)技术,我认为在这里没有用处 我还在考虑这个问题,但如果有人能提供优雅的解决方案,那就太好了 编辑。一种可能的方法是检测,尽管需要一种可靠的方法来检查此配置条目(我不知道它是如何计算的)。据我理解您的问题,您需要一种方法,允许file.bat文件确定它是否是通过在其他

问题是
调用插入符号
^
并使其加倍。在文件中,这可能是一个大问题。或者,如果一个bat没有使用另一个bat的
调用
执行,并且您想要警告用户

%cmdline%
(尽管如此,如果直接从提示符执行文件,也可以使用此方法)和(最终可以与此一起使用)技术,我认为在这里没有用处

我还在考虑这个问题,但如果有人能提供优雅的解决方案,那就太好了


编辑。一种可能的方法是检测,尽管需要一种可靠的方法来检查此配置条目(我不知道它是如何计算的)。

据我理解您的问题,您需要一种方法,允许
file.bat
文件确定它是否是通过在其他批处理文件中执行的
call
命令调用的,这样做的方法是在批处理文件中插入额外的检查代码,对吗

一个非常简单的方法是在调用方代码中的call命令之前插入一行额外的代码,以便定义一个“call flag”变量。这样,当
文件.bat中未定义此类变量时,则不会通过
调用调用

在调用方代码中:

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 
@echo关闭
setlocal EnableDelayedExpansion
设置“\u fileCheck=%~0”
如果“!\u文件检查:~-4!”=”.bAt“转到:子级”
del stackoverflow.log
启动“/b”%~dpn0.bAt”所有参数
设置计数=0
(调用:recusion&echo NEVER)1>stackoverflow.log 2>&1
回声#*从不
退出/b
:复发
设置/a计数+=1
回声+%计数%
电话:回避
:孩子
ping-n 2本地主机2>&1>nul
:循环
(
nul
:X
对于/F“tokens=1,2 delims=,=”%%L in('type stackoverflow.log')do(
设置“行=%%L”
设置“firstChar=!line:~0,1!”
如果“!firstChar!”==”+“(
设置/a最大计数=!行!
)否则如果“!firstChar!”NEQ“*”(
集合/a溢出=%%M
)
)
如果!麦克斯计数!EQU!溢流(
echo直接启动
)否则(
回音呼叫已启动
)
出口

如果我能理解您的问题:您需要一种方法,允许批处理脚本确定它是否是通过另一个批处理脚本的
调用
命令调用的。下一步
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
==> 33939966test.bat "^^%" "C&D pay 21 % VAT" "^=caret" %OS% %%OS%%
call from another script "^^%" "C&D pay 21 % VAT" "^=caret" Windows_NT %Windows_NT%
来自调用者的输出

==> 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
的内容如下(包括复制和粘贴部分):

请注意,上面的方法不是防弹的,因为我们可以想象命令行中的假阳性:

==> 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
==> 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)
技术相结合会有所帮助?

与的一样,这无法区分当前批处理文件是被调用的还是直接从被调用的批处理文件调用的。此代码仅检测执行上下文在完成时是否是批处理文件(到达此点的某个地方有一个
调用
)或命令行(没有任何
调用
,或者初始上下文是命令行)。不一样,但也许有人能从中找到更好的方法

在杰布的评论后编辑。我认为
echo
可能会有更大的问题,但事实并非如此,因此
(goto)
方法显然是一个更好的选择

@echo关闭
rem检查这是初始调用还是我们已经确定
rem批处理文件是如何启动的
rem如果已测试保存方法,请删除测试变量并转到main
如果已定义,则调用测试(
设置“startMethod=%\uuuuu callTest%”
设置“\uuuu callTest\uuuuu=”
后藤:主要
)
rem初始调用-测试例程
rem取消当前批处理上下文并检查新上下文是否正确
rem-批处理(某处有电话)
rem-命令行(无调用)
rem调用方法确定后,重新启动当前批处理
setlocal enableextensions disabledelayedexpansion
调用:getCurrentFile\u f0
(
rem取消上下文
2> 努尔(后藤)
rem上下文取消操作会干扰回显逻辑。还原
呼应
rem我们尝试读取一个不存在的变量,看看是否可以。
rem-在命令行上下文中,读取不存在的变量
rem返回变量的名称,设置我们的测试变量
rem-在批处理上下文中,读取不存在的变量不会
rem返回任何内容,并且测试变量未定义
调用集“uuu callTest_uuuu=%%{[%random%”“%random%]}%%”
如果已定义,则调用测试(
设置“\uuuu callTest\uuuuu=direct”
“%\u f0%”*
)否则(
设置“\uuuu callTest\uuuuu=call”
调用“%\u f0%”*
)
)
:getCurrentFile returnVar
设置“%~1=%~f0”
后藤:eof
rem主批次代码
:main
setlocal enableextensions disabledelayedexpansion
回显方法调用为[%startMethod%]
后藤:eof

是的,当然不是防弹的。这段代码有一个习惯性的批处理参数处理问题,它围绕着
%*

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

caller.cmd:

SET calling=1
CALL called.cmd
SET calling=
调用.cmd

IF [%calling%]==[1] SET PATH=%PATH%;.
1)
(goto)>nul
技术显示了与
调用
和直接启动相同的结果。2)
cmdline
也会产生相同的结果。3) 使用批记录