よって、そういうことを行えるフリーソフトを利用するか、 またはそういうコマンドを自作するとかしないと、とりあえずは無理なようです。
また、[7] で見つけましたが、 if 文や for 文で使われる ( ) は 複数のコマンドをブロック化するために単独で使うこともできるようです。 これによりバッチファイルから簡単なファイルの書き出しを行う 7 節の echo の例は、以下のように >> なしで書くこともできます。
こちらの方が多少見やすいですが、 この方法では ( ) 内部の echo の文中に ( ) を使うことができません (よって 7 節の echo の例の ( ) をここでは [ ] に変えてあります)。
(
echo @echo off
echo echo これは子バッチです [%%0]
echo exit /b
) > test1.bat
call test1.bat
set a=3
%a%
が「3
」
set a= 3
%a%
が「 3
」
set a =3
%a %
が「3
」
set a = 3
%a %
が「 3
」
set a = 3
%a %
が「 3
」
で削除するのを忘れないでください23。set [変数名]=
逆に、バッチファイル実行後も環境変数の設定が残るという性質を利用して、 そのコマンドプロンプトの環境変数 (特に PATH 環境変数) を設定するためのバッチファイルを使うこともできます。
とすると、
for %%a in (1 2 3) do echo [%%a][%%A]
のように表示されます。
[1][%A]
[2][%A]
[3][%A]
のような条件を書くと、バッチファイルのコマンドラインオプションの %1 が与えられなかった場合は
if %1==2 [コマンド]
と展開されてしまうので、構文エラーとなってしまいます。 よって、if 文の条件の両辺が空文字列となりうる場合は、
if ==2 [コマンド]
のように引用符で囲むといいでしょう。
if "%1"=="2" [コマンド]
if [条件] [コマンド]
else [コマンド]
if [条件] (
[コマンド]
..........
)
else (
[コマンド]
..........
)
ただし、if の実行部が 1 行で、else の実行部が複数行 (あるいはその逆) であるときは、以下のように書くことはできます。
if [条件] [コマンド] else (
[コマンド]
..........
)
とすると、最初の echo から else も含んで行末までが if 部分の実行コマンドと認識されてしまいますので、
if "%a%"=="3" echo 「3 です。」 else echo 「3 以外です。」
のように書く必要があります。
if "%a%"=="3" (echo 「3 です。」) else echo 「3 以外です。」
は、バッチファイルでも同様に
if ([条件1]) {
[ブロック1]
} else if ([条件2]) {
[ブロック2]
} else {
[ブロック3]
}
のように書くことができますし、入れ子にして
if [条件1] (
[ブロック1]
) else if [条件2] (
[ブロック2]
) else (
[ブロック3]
)
のようにすることも可能です。
if [条件1] (
[ブロック1]
) else (
if [条件2] (
[ブロック2]
) else (
[ブロック3]
)
)
しかし、オプションは 9 つまでしか認識できないわけではなく、 shift コマンドを利用すればそれより多くのオプションも使うことはできます。 例えば、1 度の shift コマンドにより 10 番目の引数が %9 に、 2 度目の shift コマンドにより 11 番目の引数が %9 になります。
なお、バッチファイルのオプションの区切りにはスペースだけでなく、 カンマも使えることに注意してください。 逆に、スペースやカンマを含む文字列をオプションとして指定したい場合は、 その部分を二重引用符 " " で囲む必要があります。 ただし、その場合二重引用符付きの文字列となりますが、 例えば %1 からその引用符を取り除いた文字列を使いたい場合は、 %~1 とします。詳しくは、help call 参照。
ちなみに上の方法だと、C 言語同様、 argc にはバッチファイル名も入れたコマンドラインオプションの個数が入ります。
set argc=0
for %%a in (%0 %*) do set /a argc+=1
のように、説明部分のバッチファイル名に当たるところを %0 を使って書けば、 後でバッチファイルの名前を変更してもこの help 部分を変更する必要はなくなります25。
@echo off
if not "%1"=="" goto run1
rem ##### 以下はヘルプメッセージ #####
:help
echo 使用法: %0 [ファイル名]
echo [ファイル名] のファイルの行をランダムに 1 行表示
exit /b 1
rem ##### 以下からが main #####
:run1
.....
test1, test2, test3, test4のような 4 つのファイルがあって、 このうち test1 と test3 だけをワイルドカードで選ぶことはできませんので、 その 2 つだけを別なディレクトリにコピーする場合は、
のようにするしかありません。 また copy コマンドは、例えば
> copy test1 dir
> copy test3 dir
のように自分自身のファイルにコピーしようとすると エラーメッセージを出して止まるのですが、 + の形式を使った場合はそうではなく、
> copy test1 .
あるいは
> copy test1+test3 .
とすると、test1 と test3 を連結した結果を test1 として上書きします。
> copy test1+test3
と制限されていたころは、 すべてのファイル名にマッチさせるワイルドカードは *.* と書いてしましたが、 今は * だけですべてのファイル名にマッチします。 ちなみに MS-DOS の頃は、* は 「拡張子がないすべてのファイル」を意味していました。
[名前 (8 文字以下)].[拡張子 (3 文字以下)]
なお、今でも *.* はすべてのファイル名にマッチするので、 現在のコマンドプロンプトに関する本でも すべてのファイル名にマッチするパターンとして *.* を紹介しているものは少なくないようです。
逆に、MS-DOS の頃の「拡張子がないすべてのファイル」を意味する * に相当するワイルドカードパターンは、現在は存在しません。
こうすると date /t の出力が tmpf というファイルに保存され、 それが set /p にリダイレクトされて環境変数 s に代入されます。
> date /t > tmpf
> set /p s= < tmpf
しかし、これを中間ファイルなしにパイプで 以下のようにやってもうまくいきません。
理由は正確にはわかりませんが、set が cmd.exe の内部コマンドなので、 パイプ渡しができないのではないかと想像しています。
> date /t | set /p s=
なお、日付はこのようにしなくても、 動的な環境変数 %date% で参照できます (3 節参照)。
とすると、a には 0 が、b には乱数値が入ります。 前者は、多分「静的」な環境変数 random を探してそれがないために 0 が代入されているのではないかと思います。
> set /a a=random
> set /a b=%random%
\
hoge というディレクトリにある "file1.txt") である場合、
\
hoge\
file1.txt)
\
hoge\
)
とすると、期待通り 1+2+3 の結果の 6 が表示されるのですが、
> set j=0
> for %a in (1 2 3) do set /a j+=%a
> echo %j%
は、「竹の茂治」とは表示されず、「%s%茂治」と表示されてしまいます。 %a を %%a としてバッチファイルで行えば 「茂治」だけが表示されます。
> set s=
> for %a in (竹 の 茂治) do set s=%s%%a
> echo %s%
これは、for 文の局所変数である %a は リストの要素に順に展開されるのに対し、 環境変数の値である %s% は、 この for 文が実行される前に展開されてしまうからで、 その時点では環境変数 s は最初の set s= によって未定義となっていますから、 上の 5. で説明した通り、 コマンドプロンプトでは「%s%」という 3 文字の文字列に展開され、 よって for 文が実行されるときは 既に展開されてしまった文字列 %s% に対して順に
が実行されてしまうことになり、 よって最後の set コマンドにより s の値は 「%s%茂治」となるわけです。
set s=%s%竹
set s=%s%の
set s=%s%茂治
この現象は、上のうまくいく例の方の for 文の set コマンドを %j% を使って
と変えても起こり、これも for 文内の %j% が for 文が実行される前に for 文の直前の値である 0 に展開されるので、 for 文では実際には
> set j=0
> for %a in (1 2 3) do set /a j=%j%+%a
> echo %j%
が実行されてしまい、結果として 6 ではなく 3 と表示されてしまいます。
set /a j=0+1
set /a j=0+2
set /a j=0+3
これを防いで、for 文内でも環境変数の値を逐次展開される変数として利用するには、 遅延展開 という機能を利用します。
デフォルトのコマンドプロンプト (cmd.exe) では、 遅延展開機能が使えるようにはなっていません (off) から、 それを on にする必要があります。 遅延展開機能を on にするには、
として、遅延展開機能が有効なコマンドインタプリタを二重に起動する
>cmd /v:on
(最初のオプション文字列はウィンドウのタイトル)
>start "遅延展開可" cmd /v:on
のようにして、そのバッチファイルの実行のみ遅延展開機能を on にする
>cmd /v:on /c test.bat
そして、for 文で逐次展開したい環境変数の値は、 %[変数]% ではなく、 ![変数]! のように ! で囲みます。例えば
のようにすれば正しく [j=6][s=123] と表示されます。 なお、バッチファイル中では、 上の 5. で説明した通り s が未定義の場合は !s! は空文字になるので、 if defined による場合分けは不要です。
> set j=0
> set s=
> for %a in (1 2 3) do (
> set /a j=!j!+%a
> if defined s (set s=!s!%a) else (set s=%a)
> rem バッチファイルなら set s=!s!%%a でよい
> )
> echo [j=%j%][s=%s%]
竹野茂治@新潟工科大学