Set one variable in another batch file - batch-file

I would like to set a variable in another batch file, if it exsists. But it works only localy in the sub batch file. How can I fix this problem?
Main.bat:
SET TEMP=""
IF EXIST SUB.bat (
CALL SUB.bat
REM Returns: TEMP="" IN MAIN
ECHO %TEMP% IN MAIN
) ELSE (
SET TEMP="DEFAULT VALUE"
)
Sub.bat:
SET TEMP="OTHER VALUE"
REM Returns: TEMP="OTHER VALUE" IN SUB
ECHO %TEMP% IN SUB
Output by calling Main.bat:
TEMP="OTHER VALUE" IN SUB
TEMP="" IN MAIN

Two issues:
Your test is incorrect. Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Try using CALL ECHO %%TEMP%% to display the altered value and look up "delayedexpansion" for endless SO items on this frequently-encountered subject.
Second issue - which impinges on the first.
TEMP and TMP are special variablenames which specify the location of a temporary-files directory. Best not to change them as unexpected results may ensue. Use another variablename.

Related

Batch Script excueting unchosen block of code

I have a batch script that checks the input of the user before running a specific block of code. Both blocks manipulate the same variables but it appears the variables of the second block are the ones that are being set even if I choose the first block to execute.
Code:
if %x == 1 goto :Block1
if %x == 2 goto :Block2
:Block1
set variable== "Works"
:Block2
set variable == "Works"
Block 2 is executing even if I input 1. Am I missing something?
Unlike many languages, batch has no concept of the end of a "procedure" - it simply continues execution line-by-line until it reaches the end-of-file. Consequently, you need to goto :eof after completing the mainline, otherwise execution will continue through the subroutine code. :EOF is a predefined label understood by CMD to mean end of file. The colon is required.

Batch File not setting variable

I'm trying to write a batch file that will simplify the generation of WebService stubs. The problem is that one of the SET commands for a variable is not setting the value. I've tried various things to get it to honour this SET but to no avail. Clearly missing something obvious. The rest of the script is working fine.
IF %1==-b (
ECHO %2
SET BINDINGS_FILE=%2
SHIFT & SHIFT
ECHO File: %BINDINGS_FILE%
IF EXIST "%BINDINGS_FILE%" (
SET BINDINGS=-b %BINDINGS_FILE%
) ELSE (
ECHO Please enter a valid Bindings file name: %BINDINGS_FILE%.
GOTO DONE
)
ECHO BINDINGS = %BINDINGS%
)
When I execute it with the following command, it prints the bindings file as %2 but the variable into which it gets SET remains empty.
generate-stubs.bat -b wsdl/Binding.xml -p com.acme.service wsdl/WebService.wsdl
wsdl/Binding.xml
File:
Please enter a valid Bindings file name: .
Done!
Any suggestions appreciated.
Batch file is setting the variable to the indicated value. BUT you are not seeing it.
In batch files lines are parsed, and then executed. Line by line or block by block (lines enclosed in parenthesis). When the parser reaches a line or a block of lines, at all points where a variable is read, the reference to the variable is removed and replaced with the value in the variable before starting to execute the block. So, if a variable changes its value inside a block, this new value will not be accesible from inside this same block. What is being executed does not include a reference to the variable but the value in the variable when the code was parsed.
To change this behaviour, and be able to read the changed value of the variable from inside the same block that changed the value, delayed expansion is needed.
When delayed expansion is enabled, the syntax to access/read a variable can be changed (where needed) from %var% to !var!. This instructs the parser not to do the initial replacement and delay the access to the value until execution of the command.
So, your code can be something like
setlocal enabledelayedexpansion
IF "%1"=="-b" (
ECHO %2
SET "BINDINGS_FILE=%~2"
SHIFT & SHIFT
ECHO File: !BINDINGS_FILE!
IF EXIST "!BINDINGS_FILE!" (
SET "BINDINGS=-b !BINDINGS_FILE!"
) ELSE (
ECHO Please enter a valid Bindings file name: !BINDINGS_FILE!.
GOTO DONE
)
ECHO BINDINGS = !BINDINGS!
)
Looks like a very old post but might save someone hours of effort...
All commands within IF statement brackets "(" ")" get executed as a single block. The variable value does get changed during execution of the IF statement block (LINE 2 till LINE 5) but the changed value can ONLY be used after the current block execution completes.
e.g. your code snippet below,
1 IF %1==-b (
2 ECHO %2
3 SET BINDINGS_FILE=%2
4 SHIFT & SHIFT
5 ECHO File: %BINDINGS_FILE%
)
6 ECHO %BINDINGS_FILE%
Although the value of "BINDING_FLAGS" is set in Line #3, but it will take effect ONLY in the next block or next command, which means, that Line #6 will display the actual value and not LINE #5

Batch If statement not working

Having a problem with an If statement in a batch file. I have several scripts, one will set a value to variable and store it to a text file to be read by another script. The value is either yes or no. That part works. When the next script executes, it first reads the line from the txt file and stores the value to a variable. That part works, I can echo the variable and see that it reads the line and stores it to the variable. Now, the next section is suppose to evaluate the variable and based on the result the script will either continue or exit. for some reason it always exits. Below is sample of the statement:
::****Check Value******
set /p _xexit=<xclean.txt
Echo %_xexit%
if %_xexit%=yes (
goto skip3
) else (
::CODE TO EXECUTE IF %_xexit%=no starts here
code
::AFTER THIS CODE EXECUTES, SCRIPT WILL EXIT
::My skip3
:skip3
echo "Exit Called"
wait
Exit
You have to double the =
if "%_xexit%"=="yes"

Handling of variables in for-loop of a Windows batch file

I've been investigating this a lot with threads on StackOverflow and the like, but although I feel I'm close to the solution, this problem is giving me headaches.
What I'm trying to do: When a specific external hard drive is connected (distinguished via VolumeSerialNumber over WMIC), the drive letter is found out, and mirroring is done via robocopy. The script is executed via double-click. This is what I have so far:
FOR /F "skip=1" %%i in ('wmic logicaldisk where VolumeSerialNumber^="XXXXXXXX" get deviceid 2^>nul') DO (
SET y=%%i
IF [%y%]==[] GOTO hdmissing
SET "backuphd=%%i"
GOTO endfor
)
:endfor
robocopy "C:\Users\Herbert\Documents" "%backuphd%\Backup\Documents" /MIR
ECHO Backup done
ECHO end
:hdmissing
ECHO Couldn't find external drive
:end
PAUSE
This way, the external HD is never detected (%y% is always an empty string). However, if I execute the script twice in the same console session, everything works as expected. But I want it to work at the first execution.
This is what I've tried so far:
Put SET y=dummy at the beginning of the script. The HD is always found, triggering a backup to C: if the HD is not actually connected (apparently SET y=%%i doesn't alter y?)
Change %y% to !y! - The HD is always found, again
Generation 3,576 of the delayed expansion problem, compounded by a contaminated environment.
There's no setlocal apparent, so y remains set in the environment after the first run - hence the 'later run characteristics different from first run' phenomenon.
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
The key in your case appears to be no setlocal enabledelayeexpansion and !y! - because !y! is just that - a literal string !y! unless delayedexpansion is invoked by the setlocal command.
(having said that,
IF [%%i]==[] GOTO hdmissing
would work just as well, as would
SET "y=%%i"
IF not defined y GOTO hdmissing
because if [not] defined var operates on the run-time value of var. "quoting the set arguments" ensures that any stray trailing spaces on the line are not included in the value assigned
)
As Magoo already pointed out, !y! doesn't work, since I forgot to enable Delayed Expansion. However, enabling it requires you to escape certain characters, which seemed quite irritating and tedious to me. It could be possible to just enclose the command in the FOR-loop with double quotes, as done in the two edits of this question, but I found out after solving it differently.
What I did was moving the block
IF [%y%]==[] GOTO hdmissing
SET "backuphd=%%i"
after :endfor. This way, it's outside of the for loop and %y% gets expanded accordingly.
Mind that this solution works only because I need just one item, and because of the programming flow.
Other useful approaches might be found in this question.
However, if you want to do the same thing: easier (though not as robust) solutions without WMIC might include
Putting a file with a specific name on the hard drive and checking for it with IF EXIST before backing up, hoping the user will not delete it, and the HD is connected to the same drive letter.
Putting the batch script on the drive itself and work with relative path names (optional: put a shortcut on the Desktop and hope again the drive is always under the same letter)

Batch Files third "If NOT" statement not reached

Hello stackoverflow community,
I am writing a batch file to do some automatic computer maintenance and have included several antivirus applications. For some reason, the third "if not" statement is never reached.
:AV
REM MSE
if not '%MSE%'=='' (
Echo Scanning for viruses using Microsoft Security Essentials.
Echo.
%MSE% -Scan -ScanType 1
Echo.
GOTO Defrag
)
REM AVG
if not '%AVG%'=='' (
Echo Scanning for viruses using AVG.
Echo.
%AVG% /COMP /QT /TRASH
Echo.
GOTO Defrag
)
REM NOD32
if not '%NOD32%'==''(
Echo Scanning for viruses using NOD32.
Echo.
if '%NOD32%'=='' GOTO NOD32NotFound
%NOD32% /aind /auto /log-file="%userprofile%\Desktop\Scan_Results.txt"
Echo.
GOTO Defrag
)
REM If all else fails...
GOTO AVNotFound
Currently, there are three blocks of codes, one for each antivirus program. Each block of code is executed only when the variable %AVG% %MSE% or %NOD32% is not empty, meaning they point to a valid file. I assign the variables using the code:
if exist "%programfiles(x86)%\AVG\AVG2012\avgscana.exe" set AVG="%programfiles(x86)%\AVG\AVG2012\avgscana.exe"
All three blocks of code works perfectly, nothing is wrong with the coding. The problem is that whatever the third block is, it never executes. So in the current example, the blocks of code go in the order of MSE, AVG, and NOD32. NOD32's block of code does not execute because it's the third block. Conversely, if I cut and paste the blocks into another order with AVG's block of code being the third block, it would not execute.
Any ideas?
Any suggestions?
Edited for clarification.
You're missing a space in the line:
if not '%NOD32%'==''(
Try:
if not '%NOD32%'=='' (
When I tried the script this line caused a failure. After changing the line, it worked.
Are the variables %MSE%, %AVG% or %NOD32% batch files? If yes, you will need to invoke them using "call" instead (for example call %AVG%)
If you call a batch file from another, the first one will exit after executing the 2nd one, unless it is called with "call".
Do any of your %AVG%, %NOD32%, or %MSE% variables have brackets in them? Could they be in the C:\Program Files (x86)\ path? A bracket will close the branch prematurely.
Place quotes around the executable part of the commands, for example:
"%MSE%" -Scan -ScanType 1

Resources