Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
920 views
in Technique[技术] by (71.8m points)

batch file - whats the difference between: %%a and %variable% variables?

for /f "tokens=*" %%a in ('find /v ":" "%appdata%gamelauncheroptions.txt" ^| find "menu=a"') do ( set usemenu=a )
for /f "tokens=*" %%a in ('find /v ":" "%appdata%gamelauncheroptions.txt" ^| find "menu=b"') do ( set usemenu=b )
for /f "tokens=*" %%a in ('find /v ":" "%appdata%gamelauncheroptions.txt" ^| find "menu=c"') do ( set usemenu=c )

Right, in this code (which may not work, that what i'm trying to find out) we have this "%%a" in that 'for' command.

First, whats the difference between %variable% and %%a?

Second, can someone explain the 'for' command to me? I have Google'd it way too much and all the explanations seem way to complicated...

What I am trying to do is pull a variable from options.txt, so i can change the menu style of my game launcher. there are 3 styles (a, b and c), so if the options.txt reads "menu=a" how can i get it to set a variable like %usemenu% to the value of a?

Thanks for any help in advance!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

%variable% are environment variables. They are set with set and can be accessed with %foo% or !foo! (with delayed expansion if enabled). %%a are special variables created by the for command to represent the current loop item or a token of a current line.

for is probably about the most complicated and powerful part of batch files. If you need loop, then in most cases for has you covered. help for has a summary.

You can

  • iterate over files: for %x in (*.txt) do ...
  • repeat something n times: for /l %x in (1, 1, 15) do... (the arguments are start, step and end)
  • iterate over a set of values: for %x in (a, b, c) do ...
  • iterate over the lines of a file: for /f %x in (foo.txt) do ...
  • tokenize lines of a file: for /f "tokens=2,3* delims=," %x in (foo.txt) do ...
  • iterate over the output of a command: for /f %x in ('somecommand.exe') do ...

That's just a short overview. It gets more complex but please read the help for that.

Variables of the form %%a (or %a if for is used outside of batch files) are very similar to arguments to batch files and subroutines (%1, %2, ...). Some kinds of expansions can be applied to them, for example to get just the file name and extension if the variable represents a file name with path you can use %%~nxa. A complete overview of those is given in help for.

On the other hand, environment variables have other kinds of special things. You can perform replacements in them via %foo:a=b% would result in %foo% except that every a is replaced by a b. Also you can take substrings: %foo:~4,2%. Descriptions of those things can be found in help set.

As to why %variables% and %%a are different things that's a bit hard to answer and probably just a historical oddity. As outlined above there is a third kind of variable, %1, etc. which are very similar to those used in for and have existed for longer, I guess. Since environment variables are a bit unwieldy to use in for due to blocks and thus heavy reliance on delayed expansion the decision probably was made to use the same mechanisms as for arguments instead of environment variables.

Also environment variables could be more expensive, given that the process has a special “environment” block of memory where they are stored in variable=value? pairs, so updating environment variables involves potentially copying around a bit of memory while the other kind of variables could be more lightweight. This is speculation, though.


As for your problem, you don't really need for here:

find /v ":" "%appdata%gamelauncheroptions.txt" | find "menu=a" && set usemenu=a

This will only run the set if the preceding command was successful, i.e. menu=a was found. This should be considerably easier than for. From what I read you're trying to look whether menu=a exists in a line that does not contain a colon and in that case usemenu should be set to a, right? (And likewise for b and c. You could try coaxing for into doing that by looping over the lines of the file or output and tokenizing appropriately to figure out the value of menu but depending on the format of the lines this can be tricky. If what you have there works in theory then you should simply stick to that. You can however use a loop around it to avoid having to repeat the same line three times for a, b and c:

for %%X in (a b c) do (
  find /v ":" "%appdata%gamelauncheroptions.txt" | find "menu=%%X" && set usemenu=%%X
)

If the file you are parsing is simple, however, with just name=value pairs in each line where : foo would be a comment, then you could use for as well:

for /f "tokens=1,* eol=: delims==" %%A in (%appdata%gamelauncheroptions.txt) do (
  if "%%A"=="menu" set usemenu=%%B
)

But that depends a little on the exact format of the file. Above snippet would now read the file line by line and for each line would discard everything after a colon (the eol=: option), use the equals sign as a token delimiter and capture two tokens: The part before the first = and everything after it. The tokens are named starting with %%A so the second one is implicitly %%B (again, this is explained in help for). Now, for each line we examine the first token and look whether it's menu and if so, assign its value to the usemenu variable. If you have a lot of possible options to support this is certainly easier to maintain :-).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...