我有first.bat
和second.bat
。
first.bat是:call second.bat
第二个是:echo %~n0
(显示正在执行的批处理的文件名)
输出为Second.bat
,但我希望它显示调用者文件名,而不是它自己的文件名。
这可能吗?
答案 0 :(得分:6)
此批处理检测调用程序脚本的名称,或者即使它直接从命令行调用
@echo off
setlocal DisableDelayedExpansion
set "func=%~0"
for /F "delims=\" %%X in ("%func:*\=%") do set "func=%%X"
if ":" == "%func:~0,1%" (
goto %func%
)
REM *** Get the name of the caller
(
(goto) 2>nul
setlocal DisableDelayedExpansion
call set "caller=%%~f0"
call set _caller=%%caller:*%%~f0=%%
if defined _caller (
set "callType=batch"
call "%~d0\:mainFunc\..%~pnx0" %*
) ELSE (
set "callType=cmd-line"
cmd /c "call "%~d0\:mainFunc\..%~pnx0" %*"
)
endlocal
)
echo NEVER REACHED
exit /b
:mainFunc
echo :mainFunc of %~nx0 arg1=%1 is called from '%caller%'/%callType%
exit /b
它使用(goto)
语句将从堆栈中删除一个级别的事实
这导致离开当前批处理文件,%~f0
将是调用者脚本的名称(并且%~0
该批处理的当前函数)或者在调用的情况下文本%~f0
命令行。
然后使用"%~d0\:mainFunc\..%~pnx0"
外部脚本
为方便使用,您可以添加帮助程序批处理文件 使用此行
在您自己的脚本中使用它@echo off
<:GetCaller <nul call GetCaller.bat myCallerVar
echo This batch was called from "%myCallerVar%"
将帮助程序批处理文件命名为 GetCaller.bat
@echo off
setlocal DisableDelayedExpansion
set "func=%~0"
for /F "delims=\" %%X in ("%func:*\=%") do set "func=%%X"
if ":" == "%func:~0,1%" (
goto %func%
)
REM *** STEP1
REM *** Get the filename of the caller of this script, needed for later restart that
(
(goto) 2>nul
setlocal DisableDelayedExpansion %= it could be reenabled by the GOTO =%
set "_returnVar=%~1"
call set "_lastCaller=%%~f0"
call set "_argToLastCaller=%%*"
call "%~d0\:Step2\..%~pnx0" %*
)
exit /b %= This is never reached =%
:Step2
REM *** STEP2
REM *** Get the filename/cmd-line of the caller of the script
(
(goto) 2>nul
(goto) 2>nul
setlocal DisableDelayedExpansion %= it could be reenabled by the GOTO =%
set "_returnVar=%_returnVar%"
set "_lastCaller=%_lastCaller%"
set "_argToLastCaller=%_argToLastCaller%"
call set "caller=%%~f0"
call set _caller=%%caller:*%%~f0=%%
if defined _caller (
set "callType=batch"
call "%~d0\:Step3batch\..%~pnx0"
) ELSE (
set "callType=cmd-line"
cmd /c "call "%~d0\:Step3batch\..%~pnx0" "
)
endlocal
)
exit /b %= This is never reached =%
:Step3batch
REM *** STEP3 Restart the requester batch, but jump to the label :GetCaller
call :GetCaller
exit /b %= This is never reached =%
:GetCaller
REM *** This uses the trick, that starting a batch without CALL will jump to the last used label
if "%_returnVar%" NEQ "" set "%_returnVar%=%_caller%"
%_lastCaller% %_argToLastCaller%
echo #6 never reached
答案 1 :(得分:5)
我认为最简单的方法是将第一批的文件名作为参数传递给第二批,就像这样。
REM First.bat
call Second.bat %~n0
REM Second.bat
echo %1
希望这有帮助!
答案 2 :(得分:4)
在调用%~n0
second.bat
的值存储在环境变量中
答案 3 :(得分:0)
如果没有复杂的系统调用来检索父进程ID,或者像KurzedMetal和BaliC帖子那样将某些内容作为参数或环境变量传递,则无法执行此操作。涉及的系统调用详见this post,您必须将DLL调用导入批处理,因此这不是一件小事。