web-dev-qa-db-ja.com

%% a変数と%variable%変数の違いは何ですか?

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

右、このコード(機能しない可能性があること、私が見つけようとしていること)では、この「%」aが「for」コマンドに含まれています。

まず、%variable%と%% aの違いは何ですか?

次に、誰かが「for」コマンドを私に説明できますか?私はグーグルでやりすぎたし、すべての説明は複雑に思える...

私がしようとしているのは、options.txtから変数をプルすることです。これにより、ゲームランチャーのメニュースタイルを変更できます。 3つのスタイル(a、b、c)があるので、options.txtが「menu = a」を読んだ場合、%usemenu%などの変数をaの値に設定するにはどうすればよいですか?

事前に助けをありがとう!

13
magicbennie

_%variable%_は環境変数です。これらはsetで設定され、_%foo%_または_!foo!_でアクセスできます(有効になっている場合は拡張の遅延あり)。 _%%a_は、現在のループ項目または現在の行のトークンを表すためにforコマンドによって作成された特別な変数です。

forはおそらく、バッチファイルの最も複雑で強力な部分です。ループが必要な場合は、ほとんどの場合forで対応できます。 _help for_には概要があります。

あなたはできる

  • ファイルを反復する:for %x in (*.txt) do ...
  • 何かを繰り返すn回:for /l %x in (1, 1, 15) do...(引数はstartstepおよびend
  • 値のセットを反復処理します:for %x in (a, b, c) do ...
  • ファイルの行を繰り返す:for /f %x in (foo.txt) do ...
  • ファイルの行をトークン化する:for /f "tokens=2,3* delims=," %x in (foo.txt) do ...
  • コマンドの出力を繰り返します:for /f %x in ('somecommand.exe') do ...

これは短い概要です。より複雑になりますが、そのためのヘルプを読んでください。

_%%a_(またはforがバッチファイルの外部で使用されている場合は_%a_)の形式の変数は、バッチファイルおよびサブルーチン(_%1_、_%2_、...)。たとえば、変数が_%%~nxa_を使用してパスを持つファイル名を表す場合に、ファイル名と拡張子のみを取得するなど、いくつかの種類の拡張をそれらに適用できます。それらの完全な概要は_help for_にあります。

一方、環境変数には他の種類の特別なものがあります。 abで置き換えられることを除いて、_%foo:a=b%_を介してそれらの置換を実行できます。結果は_%foo%_になります。また、部分文字列を取ることもできます:_%foo:~4,2%_。それらの説明は_help set_にあります。

なぜ_%variables%_と_%%a_が異なるのかについては、答えるのが少し難しく、おそらく歴史的な奇妙さだけでしょう。上で概説したように、forで使用されている変数と非常によく似た第3の種類の変数_%1_などがあり、より長く存在していると思います。環境変数はブロックのためにforで使用するのが少し扱いに​​くく、遅延拡張に大きく依存しているため、環境変数の代わりに引数と同じメカニズムを使用する決定が行われた可能性があります。

また、プロセスが_variable=value␀_ペアに格納されるメモリの特別な「環境」ブロックを持っていることを考えると、環境変数はより高価になる可能性があるため、環境変数の更新には、他の種類のメモリ変数はより軽量になる可能性があります。しかし、これは推測です。


あなたの問題に関して、あなたは本当にここにforを必要としません:

_find /v ":" "%appdata%\gamelauncher\options.txt" | find "menu=a" && set usemenu=a
_

これは、前のコマンドが成功した場合、つまり_menu=a_が見つかった場合にのみsetを実行します。これはforよりもはるかに簡単です。私が読んだものから、コロンを含まない行に_menu=a_が存在するかどうかを確認しようとしていますが、その場合、usemenuaに設定する必要がありますよね? (そしてbcの場合も同様です。ファイルまたは出力の行をループして適切にトークン化することにより、forをそれを実行するように調整することができます。 menuですが、行の形式によっては、これはトリッキーになる場合があります。理論的に機能している場合は、それをそのまま使用する必要があります。ただし、ループを使用して同じことを繰り返さないようにすることができます。 abcの3回の行:

_for %%X in (a b c) do (
  find /v ":" "%appdata%\gamelauncher\options.txt" | find "menu=%%X" && set usemenu=%%X
)
_

ただし、解析しているファイルが単純な場合は、各行に_name=value_のペアだけがあり、_: foo_がコメントになる場合、could use for同様に:

_for /f "tokens=1,* eol=: delims==" %%A in (%appdata%\gamelauncher\options.txt) do (
  if "%%A"=="menu" set usemenu=%%B
)
_

しかし、それはファイルの正確なフォーマットに少し依存します。上記のスニペットは、ファイルを1行ずつ読み取り、各行でコロンの後のすべてを破棄します(_eol=:_オプション)。等号をトークンの区切り文字として使用し、2つのトークンをキャプチャします:最初の_=_およびその後のすべて。トークンは_%%A_で始まる名前が付けられているため、2番目のトークンは暗黙的に_%%B_です(これも_help for_で説明されています)。次に、各行で最初のトークンを調べて、それがmenuであるかどうかを確認し、そうである場合は、その値をusemenu変数に割り当てます。あなたがこれをサポートする多くの可能なオプションを持っているなら、これは確かに維持するのがより簡単です:-)。

37
Joey