5.関数/サブルーチン (4)コマンド、バッチの復帰値 〜コマンドが正常終了したか確認したい〜 【コマンドプロンプト、バッチファイルを使わなきゃならなくなった人向けのメモ】
コマンド、バッチファイルの復帰値を確認したい
%ERRORLEVEL%を参照する
正常の場合は0
異常の場合は1〜255
ただし、コマンドによっては常に0を返すものもある。
正常の例
D:\MyDoc\work\#blog\test>dir ドライブ D のボリューム ラベルは データ です ボリューム シリアル番号は 94BB-7973 です D:\MyDoc\work\#blog\test のディレクトリ 2009/10/14 07:21 <DIR> . 2009/10/14 07:21 <DIR> .. 2009/10/14 07:21 0 test.txt 1 個のファイル 0 バイト 2 個のディレクトリ 323,922,767,872 バイトの空き領域 D:\MyDoc\work\#blog\test>echo %ERRORLEVEL% 0
異常の例1
D:\MyDoc\work\#blog\test>dir notexistfile ドライブ D のボリューム ラベルは データ です ボリューム シリアル番号は 94BB-7973 です D:\MyDoc\work\#blog\test のディレクトリ ファイルが見つかりません D:\MyDoc\work\#blog\test>echo %ERRORLEVEL% 1
異常の例2
D:\MyDoc\work\#blog\test>notexistcommand 'notexistcommand' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。 D:\MyDoc\work\#blog\test>echo %ERRORLEVEL% 9009
conってなに?
バッチファイルのエスケープ文字は^だ!!
バッチファイルで長い1行の処理を改行を入れて複数行に分けて書きたい
こんな方法があったのか! Windows用GNUコマンド群 「GNU utilities for Win32」
バッチファイルのパラメータ
%0はバッチファイルのファイル名となる。
C言語と同じ。Javaをやってる人は違和感があるかも。
arg1.bat
@echo off echo %0
D:\MyDoc\work\#blog\コマンドプロンプト>arg1.bat arg1.bat
バッチファイルで使用できるパラーメータは%0〜%9まで
arg2.bat
@echo off echo %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11
%10は使えないので、%1と0の文字列と解釈されてしまう。
(コマンドパラメータが1〜11だと気づかないw)
D:\MyDoc\work\#blog\コマンドプロンプト>arg2.bat a b c d e f g h i j k a b c d e f g h i a0 a1
10個以上パラメータを使いたい場合
%*を使用することで全部表示することはできる。
arg3.bat
echo %*
D:\MyDoc\work\#blog\コマンドプロンプト>arg3.bat a b c d e f g h i j k a b c d e f g h i j k
%*で表示できるけど・・・
いや、そうじゃなくて個別に10個以上パラメータを使いたいたいんだよ
個別に10個以上パラメータを使いたい場合
この場合は、shiftを使ってコマンドパラメータをずらしていく
arg4.bat
:top if {%1}=={} goto :EOF echo %1 shift goto :top
D:\MyDoc\work\#blog\コマンドプロンプト>arg4.bat a b c d e f g h i j k a b c d e f g h i j k
5.関数/サブルーチン (1)バッチファイルの呼び出し 〜体育館の裏に呼び出されました。。。〜 【コマンドプロンプト、バッチファイルを使わなきゃならなくなった人向けのメモ】
goto文ばかり使っていると訳分からなくなるので、バッチファイルを分割する。
その場合、バッチからバッチファイルを呼び出すときにはcall文を使用する。
呼び出すバッチファイルと呼び出されるバッチファイルが同じディレクトリにある場合は、ファイル名だけで
呼び出される。
拡張子は、あってもなくてもいいが、何を呼び出してるかを区別するために拡張子は書いた方がいいだろう。
カレントディレクトリにない場合は、環境変数PATHに設定すれば、ファイル名だけで呼び出される。
PATHにも設置されていない場合は、絶対パスで呼び出す。
拡張子を省略できるのは環境変数PATHEXTに設定されているものである。
D:\MyDoc\work\#blog\コマンドプロンプト\call\familyA>set pathext PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
実行環境
ディレクトリ構成
D:\MyDoc\work\#blog\コマンドプロンプト\call>tree /F 省略 ├─familyA │ child1.bat │ child2.CMD │ parent.bat │ ├─familyB │ cousin.bat │ └─familyC friend.bat
各バッチの内容
- parent.atb
call child1.bat call child1 call child2.cmd call child2 call cousin.bat call D:\MyDoc\work\#blog\コマンドプロンプト\call\familyC\friend.bat
- child1.bat
@echo 私は子供です。長男です。
- child2.CMD
@echo 私は子供です。次男です。
- cousin.bat
@echo 私はいとこです。
- friend.bat
@echo 私は友達です。
環境変数
Path=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;D:\MyDoc\work\#blog\コマンドプロンプト\call\familyB
実行結果
D:\MyDoc\work\#blog\コマンドプロンプト\call\familyA>parent.bat D:\MyDoc\work\#blog\コマンドプロンプト\call\familyA>call child1.bat 私は子供です。長男です。 D:\MyDoc\work\#blog\コマンドプロンプト\call\familyA>call child1 私は子供です。長男です。 D:\MyDoc\work\#blog\コマンドプロンプト\call\familyA>call child2.cmd 私は子供です。次男です。 D:\MyDoc\work\#blog\コマンドプロンプト\call\familyA>call child2 私は子供です。次男です。 D:\MyDoc\work\#blog\コマンドプロンプト\call\familyA>call cousin.bat 私はいとこです。 D:\MyDoc\work\#blog\コマンドプロンプト\call\familyA>call D:\MyDoc\work\#blog\コマンドプロンプト\call\familyC\friend.bat 私は友達です。
conってなに?
バッチファイルのエスケープ文字は^だ!!
バッチファイルで長い1行の処理を改行を入れて複数行に分けて書きたい
こんな方法があったのか! Windows用GNUコマンド群 「GNU utilities for Win32」
4.基本文法 (4)forでループ処理 〜回って回って回るぅ〜 【コマンドプロンプト、バッチファイルを使わなきゃならなくなった人向けのメモ】
if文とgoto文を使わず、for文を使うことができる
c:\>for /L %i in (0,1,9) do @echo %i 0 1 2 3 4 5 6 7 8 9
バッチファイルを作成するときは、%iではなく%%iにする必要がある。
for /L %%i in (0,1,9) do @echo %%i
4.基本文法 (3)ループ処理〜もう一度最初から始めるんです。 もう一度。 もう一度。〜 【コマンドプロンプト、バッチファイルを使わなきゃならなくなった人向けのメモ】
指定回数分繰り返す、こういうことが1番コンピュータにやって欲しいことだろう。
サクッとバッチファイルを作成したいものだ。
if文とgoto文を組み合わせて使う。
悪名高きgoto文、指定したラベルに移動するもの。
goto文を乱用するとあっちゃこっちゃに移動してわけわからなくなるので注意。
バッチファイル
@echo off setlocal if {%1}=={} goto USAGE set /A count=0 :TOP if %count% GEQ %1 goto END echo %count% REM 繰り返し実行したい処理 set /A count=%count%+1 goto :TOP :USAGE echo 回数を指定してください endlocal :END
比較演算子の意味は以下。
- EQU:等しい
- NEQ:等しくない
- LSS:より小さい
- LEQ:以下
- GTR:より大きい
- GEQ:以上
実行結果
c:\>D:\MyDoc\work\#blog\コマンドプロンプト\count_loop.bat 10
0
1
2
3
4
5
6
7
8
9
4.基本文法 (2)if文の注意事項 〜\Microsoft の使い方が誤っています。〜 【コマンドプロンプト、バッチファイルを使わなきゃならなくなった人向けのメモ】
通常は以下の書き方が多いと思う。
IF "%ARG1%"=="%ARG2%"
しかしこの場合値に 「"」が含まれるとエラーになってしまう。
例えば、バッチのパラメータに空白を含むディレクトリを
指定するために、「"」「"」(ダブルクォート)でくくった場合など。
なので以下のように書くようにしている。
IF {%ARG1%}=={%ARG2%}
NGなパターンのバッチファイル
IF "%1"=="%2" ( echo equal. ) ELSE ( echo not equal. )
%1,%2はコマンドパラーメターを表す特別な変数
NGなパターンの実行結果
c:\>D:\MyDoc\work\#blog\コマンドプロンプト\if-error.bat "C:\Documents and Settings\orangeclover" "C:\Documents and Settings\orangeclover" and の使い方が誤っています。 c:\>IF ""C:\Documents and Settings\orangeclover""==""C:\Documents and Settings\orangeclover"" (
OKなパターンのバッチファイル
IF {%1}=={%2} ( echo equal. ) ELSE ( echo not equal. )
OKなパターンの実行結果
c:\>D:\MyDoc\work\#blog\コマンドプロンプト\if-{}.bat "C:\Documents and Settings\orangeclover" "C:\Documents and Settings\orangeclover" c:\>IF {"C:\Documents and Settings\orangeclover"} == {"C:\Documents and Settings\orangeclover"} (echo equal. ) ELSE (echo not equal. ) equal.
「{」「}」の代わりに「'」「'」でくくる手もあるが、'09などのディレクトリもよくある。
「{」「}」もディレクトリ名に使えるのので完全ではないが、「"」「"」と「 '」「'」よりかは
「{」「}」の方が確立が低いと思う。
しかし、これでも罠が残っていた。
Windows Server 2003 x64版でテスト用にPATHを設定しようと以下のようなバッチを
組んでいた。
if {%1} == {%2} ( setlocal set PATH=%NORMAL_TEST_HOME%\bin;%PATH% endlocal ) else ( set PATH=%ERROR_TEST_HOME%\bin;%PATH% )
これが動かないのである。
Microsoft の使い方が誤っています。
なんじゃそりゃ
C:\>test.bat a b \Microsoft の使い方が誤っています。 C:\>test.bat a a \Microsoft の使い方が誤っています。
x64版だと32bitモジュールはC:\Program Files (x86)に含まれるている。
そのため環境変数が以下のようになっている
C:\>set PATH=C:\Program Files (x86)\Microsoft Visual Studio 8\VC\BIN\amd64;C:\Program Files (x86)\Mi crosoft Visual Studio 8\VC\PlatformSDK\bin\win64\amd64;C:\Program Files (x86)\Microsoft Visual Studi 〜省略〜
そうするとPATHに含まれている「(」「)」を誤認してしまうのだ。。。
回避として、IF文を2つにしたけど。。。
エラーにある通りだ。
「(」「)」を含むディレクトリをデフォルトにして、set PATHができないなんて
ホント 「Microsoft の使い方が誤っています。」だよ。
4.基本文法 (1)if文、else文 〜もしもー、それ以外ならばー〜 【コマンドプロンプト、バッチファイルを使わなきゃならなくなった人向けのメモ】
if文とelse文
else文ももちろん使える。
しばらく使えないと思い込んでた。
ifのヘルプにきっちり書いてあるんだよね。。。
以下の環境変数を設定してることを前提。
set ARG1=A
set ARG2=A
正しい使い方1
if-else-normal1.bat
IF {%ARG1%}=={%ARG2%} ( echo equal. ) ELSE ( echo not equal. )
実行結果
D:\MyDoc\work\#blog\コマンドプロンプト>IF {A} == {A} (echo equal. ) ELSE (echo not equal. ) equal.
実行時には正しい使い方2と同じに解釈される。
でも、この書き方の方が読みやすいので、こちらを使った方がよい。
正しい使い方2
if-else-normal2.bat
IF {%ARG1%}=={%ARG2%} (echo equal.) ELSE (echo not equal.)
実行結果
D:\MyDoc\work\#blog\コマンドプロンプト>IF {A} == {A} (echo eqlual. ) ELSE (echo not equal. ) eqlual.
実行するコマンドを()で囲むのがポイント
誤った使い方1
if-else-error1.bat
IF {%ARG1%}=={%ARG2%} echo equal. ELSE echo not equal.
実行結果
D:\MyDoc\work\#blog\コマンドプロンプト>IF {A} == {A} echo eqlual. ELSE echo not equal. eqlual. ELSE echo not equal.
ヘルプには以下の説明がある。
del コマンドは、改行で終了しなければならないため、次の例は、正しく動作し
ません:
delだけでなく、コマンドは、改行で終わるまでをパラメータとして認識してしまうから
ELSE以降もコマンドパラメータとして認識されてしまっている。
誤った使い方2
if-else-error2.bat
IF {%ARG1%}=={%ARG2%} echo equal. ELSE echo not equal.
実行結果
D:\MyDoc\work\#blog\コマンドプロンプト>ELSE echo not equal. 'ELSE' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。
ELSEをコマンドとして認識してしまっているのでNG
ifはコマンドだがelseは節(ifのコマンドオプション)なので誤解しやすい
入れ子も可能
set /A TEST1=%random%/10000 set /A TEST2=%random%/10000 IF {%TEST1%}=={1} ( IF {%TEST2%}=={2} ( echo TEST1=1,TEST2=2 ) ELSE ( echo TEST1=1,TEST2!=2 ) ) ELSE ( IF {%TEST2%}=={2} ( echo TEST1!=1,TEST2=2 ) ELSE ( echo TEST1!=1,TEST2!=2 ) )