10

I have first.bat and second.bat.

first.bat is: call second.bat

Second is: echo %~n0 (displays filename of the executing batch)

The output is Second.bat, but I want it to display the caller filename, not it's own.

Is this possible?

3 Answers3

10

This batch detects the name of the caller script or even if it's called directly from the command line

@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

It uses the fact, that a (goto) statement will remove one level from the stack.
This results into leaving the current batch file and %~f0 will be the name of the caller script (and %~0 the current function of that batch) or the text %~f0 in the case of called from the command line.

Then the own script is called again with "%~d0\:mainFunc\..%~pnx0"

External Script

For easy use you could add a helper batch file.
Use it in your own scripts with this line

@echo off
<:GetCaller <nul call GetCaller.bat myCallerVar
echo This batch was called from "%myCallerVar%"

Name the helper batch file 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
jeb
  • 78,592
  • 17
  • 171
  • 225
  • simplifying that to only 2 or 3 lines to embed in other script... objective just detect calling script name.... can you give an example os just the juice (grab name of the caller script)... – ZEE Jan 04 '18 at 17:52
  • 1
    @ZEE It's not possible with 2 or 3 lines, as you has to exit the current batch to fetch the caller script name and then you have to restart the current script but avoiding an endless loop. But it would be possible to move the complete code into a helper batch file. – jeb Jan 04 '18 at 18:30
  • 1
    @ZEE Added a helper script – jeb Jan 04 '18 at 19:49
6

I think the easiest way of doing this would be to pass the filename of the first batch as a parameter to the second, like this.

REM First.bat
call Second.bat %~n0

REM Second.bat
echo %1

Hope this helps!

Bali C
  • 30,582
  • 35
  • 123
  • 152
5

Store the value of %~n0 in a environment variable before calling second.bat

KurzedMetal
  • 12,540
  • 6
  • 39
  • 65