why can't i get variable value?

  • Thread starter Thread starter thinktwice
  • Start date Start date
T

thinktwice

i have a file called "IsPathRelative.bat".
it's usage like : IsPathRelative.bat yourpath, it'll set
IsPathRelative=True if the path i passed in is a relativepath(not very
accurate$B!$(Bbut works for me) else set IsPathRelative=False

i call this bath file in another batch file.

.... get path1, path2
call IsPathRelative.bat path1
if %IsPathRelative% =="True" dosomething

if %path2%=="" (
call IsPathRelative.bat path2
if %IsPathRelative% =="" do other ) <--------------------for example
if path2 is relative path, it should be True, but actually it is
False. i have traced into IsPathRelative batch file , everything's
fine . before it leaves IsPathRelative file scope, %IsPathRelative% is
still True. why this happens?
 
i have written three batch files in order to figure out why this
happened

//file1.bat
@set test=False
@if "%1" == "" @set test=True

//file2.bat
@if /i not "%1" == "" @(
@call file1.bat parameter
@echo %test%) <-----------------when i run file3.bat. this sentence
doesn't work, variable "test" seems hasn't been defined?? but it
should have been defined in file1

@call file1.bat
@echo %test%

//file3.bat
call file2.bat parameter
 
i have written three batch files in order to figure out why this
happened

//file1.bat
@set test=False
@if "%1" == "" @set test=True

//file2.bat
@if /i not "%1" == "" @(
@call file1.bat parameter
@echo %test%) <-----------------when i run file3.bat. this sentence
doesn't work, variable "test" seems hasn't been defined?? but it
should have been defined in file1

@call file1.bat
@echo %test%

//file3.bat
call file2.bat parameter

This is the effect of the way the command processor evaluates
environment variables. Specifically, it is generally done in one pass
- when the statement is initially parsed. Therefore, any alterations
to a variable that follow this evaluation are ignored. Since this is
often a problem, the processor provides a parameter to overcome this
limitation, called delayed expansion. It is invoked through the
SETLOCAL statement ...

SETLOCAL enabledelayedexpansion

and accessed through the substitution of exclamation points for
percent signs.

::file1.bat
@set test=False
@if "%1" == "" @set test=True

::file2.bat
SETLOCAL enabledelayedexpansion
@if /i not "%1" == "" @(
@call file1.bat parameter
@echo !test!)

I don't follow the logic of your examples, but that's the gist of what
you need. See the help for SET and SETLOCAL for more information and
examples.

Tom Lavedas
===========
http://members.cox.net/tglbatch/wsh/
 
thinktwice said:
i have written three batch files in order to figure out why this
happened

//file1.bat
@set test=False
@if "%1" == "" @set test=True

//file2.bat
@if /i not "%1" == "" @(
@call file1.bat parameter
@echo %test%) <-----------------when i run file3.bat. this sentence
doesn't work, variable "test" seems hasn't been defined?? but it
should have been defined in file1

@call file1.bat
@echo %test%

//file3.bat
call file2.bat parameter

Since the 'call' statement in file2 occurs within a branch of the code,
you'll need to use delayed expansion and reference the variable using
bangs '!' as opposed to the percent '%' symbols. Without it, the entire
branch of code is expanded (treated as one line) at runtime as you enter
into it which means '%test%' resolves to nul since it has yet to be
set -

-- file1
set test=False
if "%1" == "" set test=True


-- file2
if /i not "%1" == "" (
call file1 %*
echo !test!
)


-- file3
setlocal ENABLEDELAYEDEXPANSION

call file2 parameter
 
thinktwice said:
i have a file called "IsPathRelative.bat".
it's usage like : IsPathRelative.bat yourpath, it'll set
IsPathRelative=True if the path i passed in is a relativepath(not very
accurate$B!$(Bbut works for me) else set IsPathRelative=False

i call this bath file in another batch file.

... get path1, path2
call IsPathRelative.bat path1
if %IsPathRelative% =="True" dosomething

if %path2%=="" (
call IsPathRelative.bat path2
if %IsPathRelative% =="" do other ) <--------------------for example
if path2 is relative path, it should be True, but actually it is
False. i have traced into IsPathRelative batch file , everything's
fine . before it leaves IsPathRelative file scope, %IsPathRelative% is
still True. why this happens?

It's a battle between this question and date/time manipulation for #1 FAQ
status.

See Timo's FAQ in alt.msdos.batch.nt.

Batch parses the ENTIRE "IF" statement and substitutes the values of
%variable% AT THAT TIME.
THEN the "IF" statement is EXECUTED.

You are changing the value of ispathrealtive AFTER it has been parsed, and
batch executes the statement using the value AT PARSE TIME.

There are two common cures:

1. Before the IF statement (normally at the start of the batch) execute a

SETLOCAL ENABLEDELAYEDEXPANSION

statement. You may also need to add the ENABLEEXTENSIONS keyword to this
statement.

THEN use !variable! in place of %variable% to access the RUN-TIME (dynamic)
value of the variable - %variable% accesses the PARSE-TIME value.

(see
SETLOCAL /?
from the prompt, or alt.msdos.batch.nt for documentation/explanation)

This has the drawback that any environment changes made after the SETLOCAL
statement will be UNDONE when the batch terminates. (This can be bypassed -
see alt.msdos.batch.nt & alt.msdos.batch.nt FAQ for more info)

2. Use an internal routine call

....
IF .... CALL :INTERNAL
....
GOTO :EOF
:INTERNAL
:: variables values here are OUTSIDE of the context of the IF
....
GOTO :EOF

Note that the colons are important.

(see
CALL /?
from the prompt, or alt.msdos.batch.nt & alt.msdos.batch.nt FAQ for
documentation/explanation)


BTW:
are you aware that an

@ECHO OFF

statement will turn command-echoing OFF for the ENTIRE batch file - which
means you don't have to put "@" before each statement?

You can turn echoing on again with

@ECHO ON

for debugging purposes - commands will be echoed until another @ECHO OFF
statement is encountered.
 
by the way, i often use enviroment variable to pass batch file result
in the way like:

function.bat ::"function" variable is only set in function.bat
if (%function%)==(True) echo succeed

should i use delayedexpansion technique also? it works in some cases
and failed in other.
 
one thing i can make sure is the enviroment variable i use is exactly
the value i expect before leave its function batch file scope, but in
the caller batch file, it's value hasn't been changed. i even have
tried use delayedexpansion technique.
 
::test1.bat

ECHO OFF
set build=True

setlocal enabledelayedexpansion
::read configfile
::build several project and output to log file
endlocal

for /f %%i in ('findstr /s /r /i /c:"[1-9][0-9]* Error\(s\)" D:
\StateMachine\src\IDE\log\*.log') do @goto error
for /f %%i in ('findstr /s /r /c:"[1-9][0-9]* failed" D:\StateMachine
\src\IDE\log\*.log') do @goto error

goto eof

:error
@set build=False
echo %build% in test1.bat
:eof


::test2.bat
ECHO OFF
call test1.bat
ECHO %test1% in test2.bat



when i run test2.bat, i get following output:
False in test1.bat
True in test2.bat

why this happened?
 
::test2.bat
ECHO OFF
call test1.bat
ECHO %test1% in test2.bat <<< should be %build%
sorry, an typo in previous example, and this example file works, i
should find out why my real batch file doesn't work
 
thinktwice said:
by the way, i often use enviroment variable to pass batch file result
in the way like:

function.bat ::"function" variable is only set in function.bat
if (%function%)==(True) echo succeed

should i use delayedexpansion technique also? it works in some cases
and failed in other.

delayed expansion *always* *works* - the way it was intended to. When your
efforts tend to show otherwise, I'd suggest you consider examining how you
are using it and/or what, precisely, you think it is supposed to do.

/Al
 
::test1.bat

ECHO OFF
set build=True

setlocal enabledelayedexpansion
::read configfile
::build several project and output to log file
endlocal

What is endlocal doing there?
for /f %%i in ('findstr /s /r /i /c:"[1-9][0-9]* Error\(s\)" D:
\StateMachine\src\IDE\log\*.log') do @goto error
for /f %%i in ('findstr /s /r /c:"[1-9][0-9]* failed" D:\StateMachine
\src\IDE\log\*.log') do @goto error

Both these commands goto the :error routine
goto eof

:error
@set build=False
echo %build% in test1.bat
:eof


::test2.bat
ECHO OFF
call test1.bat
ECHO %test1% in test2.bat

%text1% is not set in the code above.
 
thinktwice said:
::test1.bat

ECHO OFF
set build=True

setlocal enabledelayedexpansion
::read configfile
::build several project and output to log file
endlocal

for /f %%i in ('findstr /s /r /i /c:"[1-9][0-9]* Error\(s\)" D:
\StateMachine\src\IDE\log\*.log') do @goto error
for /f %%i in ('findstr /s /r /c:"[1-9][0-9]* failed" D:\StateMachine
\src\IDE\log\*.log') do @goto error

goto eof

:error
@set build=False
echo %build% in test1.bat
:eof


::test2.bat
ECHO OFF
call test1.bat
ECHO %test1% in test2.bat



when i run test2.bat, i get following output:
False in test1.bat
True in test2.bat

why this happened?

Not 100% sure, but I think the complexity of your coding standards may be
making it more difficult to find your problems. Here are a few suggestions
for your consideration:

1) never define a label called ":eof", as ":eof" is automatically defined as
immediately following the last line in the file. If you define it
explicitly, you might be tempted to add some code to be executed on exit
like this:

if some-error-condition goto:eof
etc.
etc.
goto:eof

:eof
echo/the result is...
pause

The statements following the ":eof" label will never be executed.

2) what do you think happens when this code runs:

set test=a
if "%test%" EQU "a" (
echo/equal
) else (
echo/not equal
)

You might say that it will display the word "equal", but it will not,
because there is a trailing blank in the set statement. Do this instead:

(set test=a)
if "%test%" EQU "a" (
echo/equal
) else (
echo/not equal
)

the variable test will now contain what seemed to be the most likely and
expected value.

3) when a function returns a boolean result (i.e. true or false), there is
little benefit in prettying up the code by capitalizing the first letter,
but there is a disadvantage: unnecessary complexity. Consider this:

(set test=True)
if "%test%" EQU "true" (
echo/TRUE
) else (
echo/FALSE
)
if "%test%" EQU "false" (
echo/FALSE
) else (
echo/TRUE
)

The output will be the seemingly illogical: FALSE then TRUE. Better to use
true/false values that are less ambiguous, such as:

(set test=true)
call:showresult
(set test=)
call:showresult
goto:eof

:showresult
if defined test (
echo/test is true
) else (
echo/test is false
)

/Al
 
Back
Top