2012年4月17日火曜日

バッチメモ(Hishidama's Bat-file Memo)


バッチメモ(Hishidama's bat-file Memo) S-JIS[2006-07-07/2009-11-14] 変更履歴

DOSのコマンドをファイルに書いておき、バッチとして実行することが出来る。(UNIXのシェルスクリプトに相当)


バッチファイルの拡張子をbatにしておく。

このファイルがある場所を環境変数PATHに追加しておくか、ファイルのある場所まで移動して、
コマンドラインからファイル名を入力するか、拡張子を除いた部分を入力することによって バッチを実行する。
またはフルパスでファイル名を入力する。
ディレクトリやファイル名にスペースが入っている場合は、全体をダブルクォーテーションでくくらないと、スペースの所で区切られてしまう。(コマンド用のファイル名にスペースを入れることはあまり無いだろうが…)

C:¥temp>test.bat C:¥temp>test C:¥>C:¥temp¥test.bat C:¥>"C:¥temp¥test.bat"	…ダブルクォーテーションでくくっても可

バッチファイルの書き方

普通にコマンドプロンプトからコマンドを打つように、ファイルの中にコマンドを書いていくだけ。(通常のテキストファイルと同様)
ただし、コマンドプロンプトから直接コマンドを実行するのとは多少異なる部分もある。


@echo off

コマンドが実行時にいちいち表示されるのは邪魔なので、
定石としては、ファイルの先頭に以下のコマンドを書いておくことが多い。

@echo off

デフォルトでは、バッチファイルの実行時には コマンドを表示してからそのコマンドを実行する(UNIXのsh -xのようなもの)。
「echo off」を実行しておけば、それ以降はコマンドを表示しなくなる。
しかし「echo off」だけだと、その文(echo offそのもの)だけは表示されてしまう。そこで�/h4>

echo "start" test.bat echo "ここへは戻って来ない!"

制御を戻したい場合には、CALL命令を使う。(戻り値を返すには、「exit /b」を使用する)

他のバッチを呼び出す.bat:

echo "start" call test.bat echo "戻ってきた" %ERRORLEVEL% pause

「exit /b」でなく「exit」で終了するバッチファイルを呼び出すと、exitが呼ばれた時点でコマンドプロンプトが終了してしまう。
この場合はcmd /cを使ってバッチを呼び出してやると、「exit 戻り値」で設定した戻り値が取得できる。

exitで終了するバッチを呼び出す.bat:

echo "start" cmd /c test.bat echo "返ってきた♪" %ERRORLEVEL% pause

コマンドプロンプトのタイトルの変更方法

WindowsXPでバッチファイルをダブルクリックして実行した場合、コマンドプロンプトのウィンドウが起動して、そこで実行される。[2009-11-14]
このとき、ウィンドウのタイトルは「C:¥WINDOWS¥system32¥cmd.exe」となる。たくさんバッチファイルを実行すると、区別が付かない…。

バッチファイルの中でtitleコマンドを使うと、ウィンドウのタイトルが設定できる。

title ウィンドウのタイトル

バッチファイルの場所の取得方法

バッチファイルの在る場所からの相対パスを指定したいことがある。[2009-11-14]

例えば環境変数CDはカレントディレクトリー(実行時の作業ディレクトリー)であって、バッチファイルの場所ではない。

バッチファイルの場所は、特殊な変数「%0」を利用することで取得することが出来る。

set BATDIR=%‾dp0

%0はバッチファイルそのものを表し、‾dはそのドライブ、‾pはそのパスを表す。(‾dpでドライブ+パス)

「C:¥temp¥test.bat」内で上記のコマンドを実行すると、環境変数BATDIRは「C:¥temp¥」となる。
末尾に「¥」が付いているので、「%BATDIR%¥zzz.txt」とすると、
実際の展開時は「C:¥temp¥¥zzz.txt」となり、「¥」が2つ付いてしまう。悪影響があるどうかは、そのパスを受け取るコマンド次第。
「%BATDIR%zzz.txt」とすれば問題無いわけだが、一見すると違和感がある。

→UNIXでシェルスクリプトファイルの場所を取得する方法


バッチファイル内では環境変数がそのまま使える他、バッチの実行時引数が(読み込み専用の)変数として使える。

環境変数の使い方はsetコマンドを参照。

環境変数の他に、バッチの実行中に自動的に値が設定される変数と、for文で使用する独自の変数がある。


ストリーミング対話形式は何ですか

引数を扱う変数にはバッチの実行時引数が入っているが、サブルーチンが呼び出された場合にはそのサブルーチンの引数が入る。
UNIXとは異なり、引数を指定する際にダブルクォーテーションが付いていたら、付いたまま変数に入ってくる。

変数 内容 UNIX相当
%ERRORLEVEL% 直前に実行されたコマンド(や関数)の戻り値 $?
%0 実行コマンド名 $0
%1 %2 … %9 実行時引数(個別) $1 $2 …
%* 全引数 $* /code>」(存在する)とする。

指定方法 説明
%‾変数 %変数の値がダブルクォーテーションでくくられているとき、ダブルクォーテーションを削除したものになる。 echo %‾1
→「abc」が表示される
%‾f変数 %変数の値をフルパス(絶対パス)に変換したものになる。
..」等の相対パス指定が入っていた場合、それらが取り除かれた正しい状態になる。
echo %‾f1
→「C:¥temp¥abc」が表示される
%‾d変数 %変数の値をフルパスで扱う際のドライブ名になる。 echo %‾d1
→「C:」が表示される
%‾p変数 %変数の値をフルパスで扱う際のパス名になる。 echo %‾p1
→「¥temp¥」が表示される
%‾dp変数 %変数の値をフルパスで扱う際のドライブ+パス名になる。[2009-11-14] echo %‾dp1
→「C:¥temp¥」が表示される
%‾n変数 %変数の値のファイル名部分(拡張子なし)になる。 echo %‾n2
→「zzz」が表示される
%‾x変数 %変数の値の拡張子(ピリオド付き)になる。 echo %‾x2
→「.txt」が表示される
%‾nx変数 %変数の値のファイル名(拡張子あり)になる。 echo %‾nx2
→「zzz.txt」が表示される
%‾s変数
%‾fs変数
%変数の値を短縮形(dir /xと同等)に変換したものになる。[2008-08-02]
はずなのだが、なんだかバグがある(正しい形にならない事がある)。(WindowsXP SP3)
 
%‾a変数 %変数の値のファイルが存在するとき、そのファイルの属性になる。 echo %‾a2
→「--a------」が表示される
%‾t変数 %変数の値のファイルが存在するとき、そのファイルの更新日時になる。 echo %‾t2
→「2006/07/07 23:59」が表示される
%‾z変数 %変数の値のファイルが存在するとき、そのファイルのサイズになる。 echo %‾z2
→「5」が表示される
%‾$環境変数:変数 %変数の値のファイルが 環境変数(例えばPATHやCLASSPATH)で列挙されているディレクトリに存在するかどうか調べ、存在していればそのファイル(フルパス)になる。
「‾」と「$」の間には前述のfd等の指定を入れることが出来、それぞれの指定に従って変換される。
この機能を使うと、UNIXのwhichもどきが作れる。
%3が「help.exe」のとき、
echo %‾dpnx$PATH:3
→「C:¥WINDOWS¥system32¥help.exe」が表示される

バッチの構文

if

if 条件 コマンド if 条件 (コマンド) else コマンド

if 条件 (コマンド) else (コマンド)

if 条件 (
コマンド

) else (
コマンド

)

UNIXのifに相当。
条件が真のとき、直後のコマンドを実行する。
複数のコマンドを実行したい場合は、コマンド群を「( )」(丸括弧)でくくる。

条件が偽のとき、elseがあれば その直後のコマンドを実行する。
「if」と「else」は同じ行に無ければならない。具体的には、「if」と最初の「(」が同じ行にあり、「)」と「else」が同じ行にあればよい。
elseの直後には空白が必要。

条件には、以下の比較演算が使える。(大文字でも小文字でもよい)


xm_fileは何ですか
比較演算子
== EQU NEQ 比較
LSS LEQ
GTR GEQ
大小比較
単項演算子
NOT 否定 if not "%1" == "" echo 引数があります
DEFINED 環境変数が存在するとき、真 if defined TMP echo 有る
EXIST ファイル(やディレクトリ)が存在するとき、真
ファイル名をダブルクォーテーションでくくることも出来るが、末尾のスペースは無視される模様。
if exist zzz.txt echo 在る
ERRORLEVEL %ERRORLEVEL%が値以上
なぜこんな演算子がわざわざあるかについては、注意点を参照。
if errorlevel 1 echo エラー

ANDやORに当たるものは無いので、複雑な演算は出来ない。

両方の項が数字だけで構成されていれば、数値として比較される。
それ以外は文字列として比較される。
例えば「"1"」は数値ではない(ダブルクォーテーションは数字じゃない)ので、「1」とは異なる。

また、「/i」オプションを付けると、大文字小文字を無視して比較する。

if /i %1 equ abc (echo 一致!) else (echo 不一致)


→then部・else部で環境変数を使う場合の注意


for

for /L %変数 in (開始,増分,終了) do コマンド for /L %変数 in (開始,増分,終了) do (
コマンド

)

変数が開始〜終了まで変化し、その回数分do以降が実行される。

>for /L %i in (1,1,10) do echo %i

→1〜10が表示される。「(10,1,10)」なら10のみ、「(11,1,10)」なら一回も実行されない。


for文の変数は他の構文と比べると異色で、変数名は英字1文字。大文字と小文字は区別されるので別の変数となる。
コマンドプロンプトから直接for文を使う場合は変数は「%i」等でよいが、バッチ内に記述する場合は「%%i」のように「%」を2つ書かなければならない。

→変数(%i)の加工
→do部で環境変数を使う場合の注意


for each

for %変数 in (複数の値) do コマンド

UNIXのforに相当。
in以降の複数の値について、1個ずつ処理を行う。区切り文字にはスペース・カンマ・セミコロンが使える。

�C:¥lib2¥*.jar) do @echo %i

ワイルドカードが入っていると、そのディレクトリ(パスが指定されていない場合はカレントディレクトリ)のファイル名の一覧になる。(ファイルのみで、ディレクトリは入らない)
スペースやセミコロン「;」で(ワイルドカード入りのパスでも)複数のパスを区切ることも出来る。[2009-02-20]

>for /d %i in (C:¥*) do @echo %i

「/d」オプションを付けると、ディレクトリのみが対象になる。

>for /r %i in (*.txt) do @echo %i

「/r」オプションを付けると、サブディレクトリも再帰的に探索対象となる。

ファイルの内容

>for /f "オプション" %i in (ファイル名) do @echo %i	…ファイルの内容(各行)でループ >for /f "オプション" %i in ("文字列")   do @echo %i	…文字列を処理 >for /f "オプション" %i in ('コマンド') do @echo %i	…コマンドの実行結果(標準出力の各行)でループ

指定された対象の行ごとにループする。空行は無視される。
デフォルトでは、変数(上記の例では%i)には行の先頭の1語が入る。

オプションはダブルクォーテーションでくくって、以下のものを指定する。(スペース区切りで複数指定可能)

skip=行数 ファイルのその行数分だけスキップする。
eol=字 その文字で始まる行は、コメント行として無視する。
>for /f "eol=;" %i in (";コメント") do @echo %i 
tokens=番号 その番号個目のカラムを変数に入れる。(デフォルトでは1)
>for /f "tokens=2" %i in ("a b c") do @echo %i b

番号をカンマ区切りで列挙すると、そのカラムが変数に入れられる。
変数は最初に指定されていたものから順番に、暗黙に増える。(指定したのがiならj,k,l,…、aならb,c,d,…)

>for /f "tokens=1,3" %i in ("a b c") do @echo %i %j a c

ハイフンでカラムの範囲を指定することも出来る。

>for /f "tokens=2-4" %i in ("a b c d e") do @echo %i %j %k b c d

番号の代わりに「*」を指定すると、行の残りの部分全てになる。


EarthLinkのためのscamgrd.dllは何ですか
>for /f "tokens=1,*" %i in ("a b c d e") do @echo %i -- %j a -- b c d e
>for /f "tokens=*" %i in (test.txt) do @echo %i	…行を全部表示
delims=文字 デリミター(区切り文字)を指定する。(デフォルトではスペース)
>for /f "delims=,; tokens=1-3" %i in ("abc;def,ghi") do @echo %i %j %k abc def ghi
usebackq ファイル名指定の引用符の意味を変える。
デフォルトでは 引用符を何も付けないとファイル名指定だが、空白が入っているファイル名には対応していない。
このオプションを付けることにより、ダブルクォーテーションがファイル名指定になる。(したがって空白が入っているファイル名を指定できるようになる)
>for /f "usebackq" %i in ("ファイル名") do @echo %i	…ファイルの内容でループ >for /f "usebackq" %i in ('文字列')     do @echo %i	…文字列を処理 >for /f "usebackq" %i in (`コマンド`)   do @echo %i	…コマンドの実行結果でループ

goto

:ラベル
goto ラベル

MS-DOSには高度なループ構文は無いので、gotoでジャンプすることで対応する。

if %‾1 == abc goto match echo 不一致 goto :EOF  :match echo 一致

:EOFというラベルは、暗黙に定義されている。ここへのgotoは「バッチファイルの終了へ飛ぶ 」、すなわち「バッチを終了する」ということ。
(通常のgotoではラベル名に「:」コロンは不要だが、:EOFへのgotoには必要)

なお、「exit /b」を使えば同じくバッチを終了する。こちらの方が戻り値を返せるのでいいだろう。


switch

:ラベル
goto %環境変数%

MS-DOSにはUNIXのcaseに当たるものは無いが、gotoのラベルは変数を使って動的に変えることができるので、これで代用することが出来なくはない。

set CASE=1 goto caseA_%CASE%		…CASEの値に応じて、:caseA_1か:caseA_2へ飛ぶ :caseA_1   echo case1   goto :caseA_end :caseA_2   echo case2   goto :caseA_end :caseA_end

このやり方だと、「その他」に当たるものが出来ないが…。
(存在しないラベルへ飛ぼうとするとエラーになるから)


サブルーチン

定義 呼び出し
:ラベル
setlocal

endlocal
exit /b 〔戻り値〕
call :ラベル
call :ラベル 引数

UNIXの関数に相当。
MS-DOSには関数は無いので、サブルーチン呼び出しで代用する。
callは本来別のバッチファイルを呼び出すものだが、ラベルを指定することで自分自身の一部を別バッチとして呼び出すことが出来る。
(ラベルなので、callの位置より後にラベルがあってもよい)
(あくまでラベルなので、gotoでそのラベルへ飛ぶことも、そのまま流れてサブルーチンの中へ入ってしまうことも出来るので注意)

引数は、バッチの実行時引数の変数で参照できる。

環境変数は呼び出し元と共有される。
setlocalを使うと、そこから先の環境変数は呼び出し元には反映されなくなる。すなわち 環境変数がローカル変数のようにして扱えるようになる。
(endlocalを呼び出すと、環境変数は元の状態に戻る。endlocalを呼ばなくても、setlocalを呼び出していればバッチ終了時にendlocalの処理が暗黙に行われる)
逆に言うと、環境変数を使って呼び出し元に値を返したい場合はsetlocalは使えないので注意。

「exit /b」でバッチを終了する。callで呼ばれるときは (同一バッチファイル内であっても)別バッチ扱いなので、「exit /b」ならサブルーチンだけを終了できる。

「exit /b 戻り値」で戻り値を指定すると、呼び出し元の変数%ERRORLEVEL%に反映される。
(戻った後に他のコマンドを実行すると%ERRORLEVEL%の値は変わる可能性があるので注意)

test.bat:

@echo off echo 呼び出し前:%* call :sub aa %* bb echo 戻り値:%ERRORLEVEL% echo 呼び出し後:%* exit /b  :sub echo 呼び出された:%* exit /b 99
>test.bat foo zzz 呼び出し前:foo zzz 呼び出された:aa foo zzz bb 戻り値:99 呼び出し後:foo zzz

バッチの戻り値

バッチの一番最後で「exit /b」を呼べばバッチが終了する。
(callで呼ばれていた場合は、そのサブルーチンから抜ける)
オプションなしの「exit」は、バッチを呼び出しているコマンドプロンプト自体を終了させてしまうので要注意!)

「exit /b 戻り値」として戻り値を指定すると、バッチ呼び出し元の%ERRORLEVEL%に設定される。
戻り値を指定しなかった場合は、0が返るわけではなく、%ERRORLEVEL%の値は変わらない


また、これはバッチ処理の戻り値ではないことに注意!

「exit /b 戻り値」でどんな戻り値を返そうとも、バッチ処理自体は正常に終わっているので終了コードは正常(0)なのである。
バッチとしてのエラー(存在しないラベルに飛ぼうとしたとか)が発生した場合に、終了コードがエラーコードになる。

つまり、以下のような書き方には注意を要する。

>test.bat || echo fail

test.batが文法的におかしくて失敗した場合にメッセージを出したいならこれでいいが、
test.batの中で「exit /b 1」のように0以外の値を返したことによってメッセージを出したいなら、これではダメ。
後者の扱いをしたいのであれば、以下の様にすべき。

>test.bat & if errorlevel 1 echo fail	…test.batの戻り値が1以上のとき「echo fail」を実行

ちなみに、以下のような書き方は、分かりにくいが、やはりダメ。

>test.bat & if %ERRORLEVEL% neq 0 echo fail
>test.bat & echo %ERRORLEVEL%

なぜなら、環境変数はその行全体の実行開始前に展開されるから。
つまり実行前に%ERRORLEVEL%の値が0だったとすると、以下のように展開されてから実行されることになる。

>test.bat & if 0 neq 0 echo fail
>test.bat & echo 0

したがって、test.batがどんな値を返して(%ERRORLEVEL%にセットされて)も、実行前の値で「&」以降が処理されるということになる。
(この為に、エラーコードチェックに関してはERRORLEVELという演算子がわざわざ用意されているわけだ。これなら値の取得自体はif文の実行時に行うわけだから。)


これはその他の環境変数を使う場面でも同様に起こり得る。特にif文やfor文ではよく勘違いしてやってしまう。「help for」「for /?」でもわざわざ例示されているくらいだ。

>set var=aaa >set var=bbb & echo %var%		→「set var=bbb & echo aaa」と展開されてから実行される aaa >echo %var% bbb				→「set var=bbb」が実行されなかったわけではないので、後から見ればちゃんとセットされている
set var=1 if %var% == 1 (			→「if 1 == 1 (  set/a var=%var% + 2		   set/a var=1 + 2  echo %var%			   echo 1 )				  )」と展開されてから実行される
set list= for %%i in (aa bb) do @set list=%list%;%%i	→「for %i in (aa bb) do @set list=;%i」と展開されてから処理されるので、 echo %list%				 �/b>

@echo off more

実行例:

> type aaa.txt | test_more a1 a2  > test_more < aaa.txt a1 a2

for文への入力に標準入力を使いたい場合は、標準入力のデータをそのまま標準出力へ出力するコマンドを利用する。
例えばfindstrを使う。(UNIXならcatが使えそうな気がするが、MS-DOSのtypeは標準入力を使えない)

test_echo.bat:

@echo off for /f %%i in ('findstr .*') do echo %%i

実行例:

> type aaa.txt | test_echo a1 a2  > test_echo < aaa.txt	…なぜか何も出力されない

パイプを使ったリダイレクションはちゃんと動くのに、ファイルからの入力は何故か何も出力されない…。

とりあえず、バッチ内部でパイプを経由してやると上手くいくっぽい。

test_echo2.bat:

@echo off findstr .* | for /f %%i in ('findstr .*') do @echo %%i

実行例:

> type aaa.txt | test_echo2 a1 a2  > test_echo2 < aaa.txt a1 a2

ただ このやり方だと、doの後ろでcallを使ってラベルに飛ぼうとすると「バッチ スクリプト外でバッチ ラベルを呼び出すことはできません。」という実行時エラーになる。
どうやら、パイプの後ろは別バッチのような扱いになるらしく、したがってラベルも別空間になるので認識できないっぽい。

なかなかベストな解決方法が見つからない…(嘆)


技術メモへ戻る / 自作バッチへ行く
メールの送信先:ひしだま

 

 

 

 

 

 

 

 

 



These are our most popular posts:

cronを使ってWalbrixを自動停止する方法 - Walbrix

lvcreate -n portage -L 4G wbvg mkfs.xfs /dev/wbvg/portage mount /dev/wbvg/ portage /usr/portage wget -O - : bit.ly/91BbXy | tar xvpf - --lzma -C /usr. ダウンロードにはしばらくかかります。コマンドプロンプトにもどってきたら portage の ダウンロード ... read more

クロスコンパイル メモ - MLEXP Wiki

Linux 上で Windows のモジュールをコンパイルする方法は Google 先生に聞くと結構 出てくるけど、その逆がなかなか出てこない。 ..... プロンプトに戻ってこないので、停止 させるときは Ctrl + C で。 Windows 側の Eclipse には RSE プラグインをインストール。 RSE を取得。 ... gdb hello (だーっと表示される) (gdb) ← このプロンプトが表示される。 read more

コマンドプロンプトを使ってみよう! -バッチファイル-

MS-DOSとの関係、コマンドプロンプトの使用方法やバッチファイル作成方法など、ぜひ 覚えて使ってみよう! ... echoは、標準出力(画面)にコマンドプロンプトや各種メッセージ を表示するかどうか制御するコマンドである。 通常の ... C:¥echo echoはオン ・・・ echo文そのものが表示される echoはオン ・・・echoの実行結果. C:¥echo. ・・・空行 ではなくecho文そのものが表示される .... 元のバッチファイルに戻ってくる事ができない 。 read more

ファイルの更新日付の取得について (DOSプロンプト活用相談室LOG)

FPCUのPCユーザー交流スペースは新コミュニティ「folomy」内に ... read more

Related Posts



0 コメント:

コメントを投稿