Question 1
You are not passing the variable, you are merely passing its value. But the two batch scripts share the same environment context, hence the variable is also available in the called one.
Question 2
Yes, you can call it global in the environment context.
To localise environments use setlocal/endlocal, like in the following example:
caller.bat:
@echo off
set "VAR=foo"
echo CALLER: Variable before call: "%VAR%"
call callee.bat "%VAR%"
echo CALLER: Variable upon return: "%VAR%"
exit /B
callee.bat:
setlocal
echo CALLEE: Passed argument: "%~1"
echo CALLEE: Original variable: "%VAR%"
set "VAR=bar"
echo CALLEE: Modified variable: "%VAR%"
endlocal
exit /B
When running caller.bat, the output is going to be:
CALLER: Variable before call: "foo"
CALLEE: Passed argument: "foo"
CALLEE: Original variable: "foo"
CALLEE: Modified variable: "bar"
CALLER: Variable upon return: "foo"
If you removed setlocal and endlocal from callee.bat, the last line would show bar.
Question 3
Yes, you can think of the callee as it was embedded in the caller, with respect to the environment. When you do that with the above example scripts you will see the result is exactly the same.
But:
When it comes to block context, meaning parenthesised ( blocks of code ) or concatenated & commands, simply copying the callee into the caller does not work. This has nothing to do with the environment but with the way variables are expanded (read).
If call appears in a code block (like the body of a for loop for example), the callee is not executed in the block context of the caller, it starts a new block context. As soon as the callee terminates, the block context of the caller is restored. Let us take the above examples and modify them a bit:
caller.bat:
@echo off
set "VAR=foo"
(
echo CALLER: Variable before call: "%VAR%"
call callee.bat "%VAR%"
echo CALLER: Variable upon return: "%VAR%"
)
exit /B
callee.bat:
echo CALLEE: Passed argument: "%~1"
echo CALLEE: Original variable: "%VAR%"
set "VAR=bar"
echo CALLEE: Modified variable: "%VAR%"
exit /B
The call command line in the caller is now placed inside of a parenthesised block, the callee does not contain environment localisation (setlocal/endlocal), so one might expect the last returned line to show bar. But in fact it does not:
CALLER: Variable before call: "foo"
CALLEE: Passed argument: "foo"
CALLEE: Original variable: "foo"
CALLEE: Modified variable: "bar"
CALLER: Variable upon return: "foo"
As soon as the last echo command line in the caller is moved after the closing ), the output holds bar. As said, all this has got nothing to do with the environment. This is caused by the fact that the entire (/) block is read at once and all variables are expanded (meaning replaced by their values) immediately, hence modification of variables is not reflected within that block. You can simply prove this by typing set "VAR=value" & echo "%VAR%" into the command prompt: the first time executed, the result will be "", because the &-concatenated line/block is read at once and %VAR% is immediately replaced by its current value, which is nothing at the first time, then execution of the commands start; when you execute it a second time, VAR already contains the string value from the beginning, so you will receive value as the result. This way of reading variables is often referred to as normal or immediate expansion, or also to percent expansion due to the enclosing %% signs of the variable.
There is a way to change this behaviour to something closer to other (real) programming languages, namely delayed expansion. Using that, you can assign or change a variable and access its value immediately, even in blocks. At first this feature needs to be enabled by the setlocal command (or alternatively, in command prompt, by the /V switch of cmd). Then it has to be actually used by enclosing the variable in a pair of exclamation marks, like !VAR!. Note that you can still use percent expansion when delayed expansion is enabled.
To apply that to the above example, it may look like that:
caller.bat:
@echo off
setlocal EnableDelayedExpansion
set "VAR=foo"
(
echo CALLER: Variable before call: "%VAR%"
call callee.bat "%VAR%"
echo CALLER: Variable upon return, but immediate expansion: "%VAR%"
echo CALLER: Variable upon return, using delayed expansion: "!VAR!"
)
endlocal
exit /B
callee.bat:
echo CALLEE: Passed argument: "%~1"
echo CALLEE: Original variable: "%VAR%"
set "VAR=bar"
echo CALLEE: Modified variable: "%VAR%"
exit /B
The output would now be:
CALLER: Variable before call: "foo"
CALLEE: Passed argument: "foo"
CALLEE: Original variable: "foo"
CALLEE: Modified variable: "bar"
CALLER: Variable upon return, but immediate expansion: "foo"
CALLER: Variable upon return, using delayed expansion: "bar"
Note: Although the block context has absolutely nothing to do with the environment, I still wanted mention this, because it affects the way variables are expanded/read.