これは、コマンドプロンプト(cmd.exe) Advent Calendar 2015 - Qiitaの6日目の記事です。
※Windows 10 Home 64bit 搭載のcmd.exeにて検証を行っています。

### set /? ``` cmd.exe 環境変数を表示、設定、または削除します。 SET [変数名=[文字列]] 変数名 環境変数名を指定します。 文字列 変数に割り当てる文字列を指定します。 現在の環境変数を表示するには、パラメーターを指定せずに SET と入力してください。 コマンド拡張機能を有効にすると、SET は、次のように変更されます: 等号や値を指定せずに、変数名だけを指定して SET コマンドを実行すると、 SET コマンドに指定された名前にプレフィックスが一致するすべての変数の値が 表示されます。たとえば、 SET P と入力すると、文字 'P' で始まるすべての変数が表示されます。 変数名が現在の環境に見つからない場合は、SET コマンドは、ERRORLEVEL を 1 に設定します。 SET コマンドでは、変数の名前に等符号を使用することはできません。 SET コマンドには、2 つの新しいスイッチが追加されています: SET /A 式 SET /P 変数=[プロンプト文字列] /A スイッチは、等号の右側の文字列が、評価する数式であることを 指定します。式の評価はごく単純で、次の操作がサポートされます。 操作は、優先順位の高い順に示されています: () - グループ化 ! ~ - - 単項演算子 * / % - 算術演算子 + - - 算術演算子 << >> - 論理シフト & - ビット演算子 AND ^ - ビット演算子排他的 OR | - ビット演算子 OR = *= /= %= += -= - 代入 &= ^= |= <<= >>= , - 式の区切り記号 論理演算子またはモジュール演算子を使う場合は、式文字列を 引用符で囲む必要があります。式内の数値以外の文字列は環境変数文字列として 処理され、使用される前に数値に変換されます。 指定された環境変数名が現在の環境で定義されていない場合は、 値として 0 が使用されます。 これにより、いくつもの % 記号を入力して値を取得しないでも、 環境変数の値を算術演算に使うことができます。 コマンド スクリプト外でコマンド ラインから SET /A を実行すると、 式の最終的な値が表示されます。 割り当て演算子を使うには、割り当て演算子 の左側に環境変数名が必要です。 数値は 10 進数ですが、プレフィックスとして 0x を付けると 16 進数、0 を付けると 8 進数になります。従って、0x12 は 18、 あるいは 022 と同じです。 8 進表記を使う場合は、注意してください。08 や 09 は、8 と 9 が有効な 8 進数ではないため、 有効な数値ではありません。 /P はユーザーによって入力された入力行を変数の値として設定できるようにします。 入力行を読み取る前に、指定されたプロンプト文字列を表示します。プロンプト文 字列は空でもかまいません。 環境変数の置換は、次のように拡張されます: %PATH:文字列 1 = 文字列 2% は、PATH 環境変数を展開し、その結果に含まれるすべての "文字列 1" を "文字列 2" に置き換えます。 "文字列 2" に空の文字列を指定すると、展開された出力からすべての "文字列 1" を削除することができます。 "文字列 1" をアスタリスクで始め、展開された出力の先頭から、文字列 1 の残りの部分 が最初に現れるまでのすべてを一致させることもできます。 また、展開の副文字列を指定することもできます。 %PATH:~10,5% は、PATH 環境変数を展開し、展開結果の 11 番目 (オフセット 10) の文字 から始まる 5 文字だけを使います。長さが指定されなかった場合は、変数の 値の残りの長さを既定値とします。オフセットまたは長さのどちらかが負の値 の場合、環境変数の値の長さに指定されたオフセットまたは長さをたしてその 数を使います。 %PATH:~-10% は、パス変数の最後の 10 文字が展開されます。 %PATH:~0,-2% は最後の 2 文字以外のすべてが展開されます。 最後に、遅延環境変数の展開が追加されました。このサポートは常に既定で 無効になっていますが、CMD.EXE の /V: のコマンド ライン スイッチを使 って有効または無効にできます。 CMD /? を参照してください。 遅延環境変数の展開は、実行時ではなく、テキスト行を読み取るときに展開 されるという現在の制限を避けるために役立ちます。 次の例は即時変数展開の問題を説明しています。 set VAR=before if "%VAR%" == "before" ( set VAR=after; if "%VAR%" == "after" @echo If you see this, it worked ) この例は、論理的には IF 文が別の IF 文の本体に含まれる複合文なので、 両方の IF 文の %VAR% が、最初の IF 文を読み取ったときに展開されます。 このため、メッセージは決して表示されません。 複合文の中の IF では "before" と "after" が比較され、 決して等しくはなりません。 同様に次の例も期待したようには動作しません。 set LIST= for %i in (*) do set LIST=%LIST% %i echo %LIST% この例では、現在のディレクトリのファイルの一覧は作成されず、代わりに最後 に見つけられたファイルが LIST 変数に設定されます。 これは %LIST% が FOR 文が読み取られるとき、 一度だけ展開され、そのときは LIST 変数が空だからです。 つまり、実際に実行されている FOR ループは for %i in (*) do set LIST= %i で、LIST に最後に見つけられたファイルを設定し続けているだけです。 遅延環境変数の展開では、実行時に環境変数を展開するために異なった文字 (感嘆符) を使うことができます。 遅延環境変数の展開が有効な場合、上記の 例は次のように書くと意図したように動作します。 set VAR=before if "%VAR%" == "before" ( set VAR=after if "!VAR!" == "after" @echo If you see this, it worked ) set LIST= for %i in (*) do set LIST=!LIST! %i echo %LIST% コマンド拡張機能が有効な場合、SET によって表示される変数の一覧には 現れないいくつかの動的な環境変数があります。 これらの変数の値は、変数の値が展開されるときに 動的に計算されます。 ユーザーがこれらの名前の変数を明示的に定義する場合、 その定義は下記の動的な定義を無効にします。 %CD% - 現在のディレクトリ文字列に展開します。 %DATE% - DATE コマンドと同じフォーマットで現在の日付に展開します。 %TIME% - TIME コマンドと同じフォーマットで現在の時刻に展開します。 %RANDOM% - 0 から 32767 の間の任意の 10 進数に展開します。 %ERRORLEVEL% - 現在の ERRORLEVEL の値に展開します。 %CMDEXTVERSION% - 現在のコマンド プロセッサ拡張機能のバージョン番号に 展開します。 %CMDCMDLINE% - コマンド プロセッサを起動したオリジナル コマンド ライン に展開します。 %HIGHESTNUMANODENUMBER% - このコンピューター上の最大の NUMA ノード番号に展開します。 ```普通に環境変数を割り当てる構文はおいておいて、その他大切なことがいろいろと紛れています。

#### ①set /a で計算ができる ``` /A スイッチは、等号の右側の文字列が、評価する数式であることを 指定します。式の評価はごく単純で、次の操作がサポートされます。 操作は、優先順位の高い順に示されています: () - グループ化 ! ~ - - 単項演算子 * / % - 算術演算子 + - - 算術演算子 << >> - 論理シフト & - ビット演算子 AND ^ - ビット演算子排他的 OR | - ビット演算子 OR = *= /= %= += -= - 代入 &= ^= |= <<= >>= , - 式の区切り記号 ```例) ```dosbatch C:\Users\kunst>set /a (1 + 2 * 12) * 3 75 ```もしくは ```dosbatch C:\Users\kunst>set /a RESULT=(1 + 2 * 12) * 3 75 C:\Users\kunst>echo %RESULT% 75 ```
#### ②環境変数に対する文字列の置換ができる ``` 環境変数の置換は、次のように拡張されます: %PATH:文字列 1 = 文字列 2% は、PATH 環境変数を展開し、その結果に含まれるすべての "文字列 1" を "文字列 2" に置き換えます。 "文字列 2" に空の文字列を指定すると、展開された出力からすべての "文字列 1" を削除することができます。 "文字列 1" をアスタリスクで始め、展開された出力の先頭から、文字列 1 の残りの部分 が最初に現れるまでのすべてを一致させることもできます。 ```例) ```dosbatch C:\Users\kunst>set A=HOGEHOGE C:\Users\kunst>echo %A% HOGEHOGE C:\Users\kunst>echo %A:GE=aa% HOaaHOaa ```
#### ③環境変数から部分文字列を抜き出すことができる ``` また、展開の副文字列を指定することもできます。 %PATH:~10,5% は、PATH 環境変数を展開し、展開結果の 11 番目 (オフセット 10) の文字 から始まる 5 文字だけを使います。長さが指定されなかった場合は、変数の 値の残りの長さを既定値とします。オフセットまたは長さのどちらかが負の値 の場合、環境変数の値の長さに指定されたオフセットまたは長さをたしてその 数を使います。 %PATH:~-10% は、パス変数の最後の 10 文字が展開されます。 %PATH:~0,-2% は最後の 2 文字以外のすべてが展開されます。 ```例) ```dosbatch C:\Users\kunst>set A=ABCDEF C:\Users\kunst>echo %A% ABCDEF REM 先頭から2文字 C:\Users\kunst>echo %A:~0,2% AB REM 2文字目から2文字 C:\Users\kunst>echo %A:~1,2% BC REM 2文字飛ばして3文字目から残り全部 C:\Users\kunst>echo %A:~2% CDEF REM 最後2文字 C:\Users\kunst>echo %A:~-2% EF REM 最後5文字のうちの先頭3文字 C:\Users\kunst>echo %A:~-5,3% BCD ```
#### ④遅延環境変数の使い方 ``` 遅延環境変数の展開では、実行時に環境変数を展開するために異なった文字 (感嘆符) を使うことができます。 遅延環境変数の展開が有効な場合、上記の 例は次のように書くと意図したように動作します。 set VAR=before if "%VAR%" == "before" ( set VAR=after if "!VAR!" == "after" @echo If you see this, it worked ) set LIST= for %i in (*) do set LIST=!LIST! %i echo %LIST% ```遅延環境変数の展開が有効の場合(cmd /V:ON もしくは SETLOCAL ENABLEDELAYEDEXPANSION)、変数を「%」の代わりに「!」で囲むことによって遅延環境変数を使用することができます。※cmd /?やsetlocal /?も参照のこと※詳細は明日の「setlocal /?」で取り上げようと思います。

#### ⑤各種動的な組み込み変数 ``` コマンド拡張機能が有効な場合、SET によって表示される変数の一覧には 現れないいくつかの動的な環境変数があります。 これらの変数の値は、変数の値が展開されるときに 動的に計算されます。 ユーザーがこれらの名前の変数を明示的に定義する場合、 その定義は下記の動的な定義を無効にします。 %CD% - 現在のディレクトリ文字列に展開します。 %DATE% - DATE コマンドと同じフォーマットで現在の日付に展開します。 %TIME% - TIME コマンドと同じフォーマットで現在の時刻に展開します。 %RANDOM% - 0 から 32767 の間の任意の 10 進数に展開します。 %ERRORLEVEL% - 現在の ERRORLEVEL の値に展開します。 %CMDEXTVERSION% - 現在のコマンド プロセッサ拡張機能のバージョン番号に 展開します。 %CMDCMDLINE% - コマンド プロセッサを起動したオリジナル コマンド ライン に展開します。 %HIGHESTNUMANODENUMBER% - このコンピューター上の最大の NUMA ノード番号に展開します。 ```書いてある通りです。環境変数のため、もちろん置換や部分文字列の取得などもできます。 ```dosbatch C:\Users\kunst>echo %DATE% 2015/12/06 C:\Users\kunst>echo %DATE:/=% 20151206 ```