问题
Inside Test.txt reads a URL on the first line, theres more but for this it unimportant.
setlocal EnableDelayedExpansion
set browser=chrome.exe
set i=0
for %%f in (Test.txt) do (
set i=0
for /F "delims=" %%l in (%%f) do (
set /A i+=1
set line!i!=%%l
))
::the above read the contents of Test.txt and saved each line to a different Variable made up of two variables
set x=0
:ReadLines
if %x% gtr %i% (
goto Completed)
set /a x+=1
set /a odd=%x%%%2
if %odd%==1 (
set Address=!line%x%!
echo !Line%x%!
::the above echo's back the URL from the Text File
echo %Address%
::but the above here, echo's back nothing at all,(which then is either echo is off or echo is on) even though %Address% has been set to !Line%x%!
pause
::when i try to use !Line%x%! in my code, like the start code below, it returns nothing instead of the URL
start %browser% %Address% >nul 2>&1
start %browser% !Line%x%! >nul 2>&1
::neither start code works unfortunately and that's my ISSUE
ping localhost -n 2 >nul
goto ReadLines
)
:Completed
::Continue or Whatever...
so my question: Does anyone know why, when echoed, !Line%x%! returns the values it should, but when called uppon for a command such as, start %browser% %Address%, that it returns nothing? BTW you can run the above code just put some link in a txt doc named 'Test.txt' and you'll see my issue for yourself And Sorry if it looks kind of ugly to anyone, i really just threw this together for someone but then ran into this error and need to solve it for this for them. Any Help is wanted, Thanks!
回答1:
@ECHO OFF
setlocal EnableDelayedExpansion
set browser=chrome.exe
set i=0
for %%f in (q20300102.txt) do (
set i=0
for /F "delims=" %%l in (%%f) do (
set /A i+=1
set line!i!=%%l
))
::the above read the contents of Test.txt and saved each line to a different Variable made up of two variables
set x=0
:ReadLines
if %x% gtr %i% (
goto Completed)
set /a x+=1
set /a odd=%x%%%2
if %odd%==1 (
set Address=!line%x%!
echo !Line%x%!
REM the above echo's back the URL from the Text File
echo %Address%
REM but the above here, echo's back nothing at all,(which then is either echo is off or echo is on) even though %Address% has been set to !Line%x%!
REM pause
REM when i try to use !Line%x%! in my code, like the start code below, it returns nothing instead of the URL
ECHO start %browser% %Address%
ECHO start %browser% !Line%x%!
REM neither start code works unfortunately and that's my ISSUE
ECHO ping localhost -n 2
)
goto ReadLines
:Completed
::Continue or Whatever...
GOTO :EOF
Fundamental delayedexpansion
problem. In any compound statement (ie. a parenthesised group of statements) any occurrence of %var%
is replaced by the value of var
at the time the statement is PARSED, and THEN it is executed.
Consequently, when x=1, odd
wil be set to 1, the statement group will be parsed and echo %Address%
will have %address%
replaced by the THEN-current value of address
- but address
is not yet assigned a value, since the code is only being PARSED - it has not yet been RUN.
Similarly, start %browser% %Address%
HAS a value for browser
and that value IS substituted, but address
is not assigned, so is replaced by [nothing].
At the end of the parenthesised code, yo return to :readlines
with x=1
. This is incremented and x
is assigned 2
. This is not odd as far as I've ever experienced, so the entire parenthesised code is skipped and batch proceeds to the following line. In batch, reaching a label does not "end a procedure" so it simply charges on and rockets off to the end of the file.
In my code above, I've
- Set the filename to
q20300102,txt
to suit my system. - Replaced the
::
commenting style withREM
because in some implementations, a broken-label (::-comment) causes the compound statement to be terminated. - Removed the redirectors to allow the
START
andPING
lines to beECHO
ed (and inserted theECHO
keyword) - Moved the
GOTO readlines
outside of the compound where it will force a loop regardless of whetherx
is odd or not.
Since you gave no example of a line in your Test.txt, I made my own q20300102.txt
which contains:
Address_one
Address_two
Address_three
Address_four
Address_five
Address_six
Address_seven
Address_eight
Address_nine
and ran the above, which yielded
Address_one
ECHO is off.
start chrome.exe
start chrome.exe Address_one
ping localhost -n 2
Address_three
Address_one
start chrome.exe Address_one
start chrome.exe Address_three
ping localhost -n 2
Address_five
Address_three
start chrome.exe Address_three
start chrome.exe Address_five
ping localhost -n 2
Address_seven
Address_five
start chrome.exe Address_five
start chrome.exe Address_seven
ping localhost -n 2
Address_nine
Address_seven
start chrome.exe Address_seven
start chrome.exe Address_nine
ping localhost -n 2
(I've broken the actual output by iteration for a little more clarity)
So - the response is
Linex content
Address content (note - as it stood when the (statement) was PARSED)
Start statements including the elements just described
Ping statement
So this should get you on the path to solving your problem...
回答2:
In short: "you need to use Delayed Expansion in order to get the value of a variable that was modified inside a block"; this is a basic variable management behavior in Batch files:
if %odd%==1 (
set Address=!line%x%! <- "Address" variable was modified inside this block
- - - - - -
echo %Address% <- This not work, you need Delayed Expansion here:
echo !Address!
- - - - - -
)
回答3:
1 - Unless you intend to iterate over a group of files, your %%f
loop in unnecesary. And if you intend to iterate over a group of files, then the second set i=0
will reset the counter for each file.
2 - As stated in previous answers, when a block of code (everything between opening and closing parenthesis) is readed, every variable is replaced with its current value (at the time of reading the block!) and all block is executed one or more times without changes in the variables, as the code that is being executed does not contain variables, just its value. This behaviour has two exceptions: variables referenced as !var!
when delayed expansion is active, and contorl variables declared in for
command.
Nothing to add to the other answers on why your code has problems. Magoo and Aacini answers reflect where your problems are based on correct usage of variables with delayed expansion. Every variable modified inside a block needs to be accessed with delayed expansion sintax to retrieve the modified value.
Following code reflects the other option, usage of for
variables to elude delayed expansion problems.
@echo off
setlocal EnableDelayedExpansion
set "i=0"
for /F "delims=" %%l in (test.txt) do (
set /A "i+=1"
set "line!i!=%%l"
)
for /l %%x in (1 1 %i%) do (
set /a "odd=%%x %% 2"
if !odd!==1 (
set "Address=!line%%x!"
echo !line%%x!
echo !Address!
echo ---------------
)
)
来源:https://stackoverflow.com/questions/20300102/batch-variable-inside-a-variable-not-working-when-called