badノウハウならぬbatノウハウです。
忘れたことにやってくるbat作成のために良さそうなノウハウを見つけ次第追記します。
(何かあったら教えてくださいな)
echoさせない
行頭に@
を付けても出力が抑制されますが、面倒なので文頭にこれを書いておきましょう。
@echo off
以降のサンプルコードは全て行頭にこれが書いてあるものと思ってください。
遅延環境変数を使う
色んな方が説明してくださってるので端折ります。
(特定単位で解釈してるからだとか)
忘れたころに使うとほぼ間違えなくはまります。
set count=0
for %%a in (1, 2, 3) do (
set /a count+=1
echo %count%
)
> bad.bat
0
0
0
rem 遅延環境変数を使えるようにする
setlocal enabledelayedexpansion
set count=0
for %%a in (1, 2, 3) do (
set /a count+=1
rem ↓遅延環境変数!
echo !count!
)
> good.bat
1
2
3
どうでもいいですが、謎の魔法ではなく「enable delayed expansion」です。
引数
shで言うところの$1, $2, ... , $@, $*
。
ほぼ同じで、全部の引数を取りたいときは$*
、各引数は$1, $2, ...
です。
echo %1!
> sample.bat hoge
hoge!
終了ステータス
shで言うところの$?
。
errorlevel
に入ってます。
exit
の引数として渡した値が終了ステータスになります。
rem bオプションを付けると呼び出し元プロセスを終了させない
rem (付けないと呼び出し元プロセスまで終了させられる)
exit /b 5
> sample.bat
> echo %errorlevel%
5
関数っぽいもの(サブルーチン)
関数は存在しないそうです。
現代っ子プログラマーとしては非常につらいですね…。
ですが、ラベルをうまく利用すると関数っぽく処理を分割して書けます。
call :hello Hoge
call :hello Huga
call :hello Piyo
exit /b
:hello
echo Hello, %1!!
exit /b
> sample.bat
Hello, Hoge!!
Hello, Huga!!
Hello, Piyo!!
setlocal
も合わせて使うとなお良さそうですね。
set one=1
echo %one%
call :local
echo %one%
exit /b
:local
setlocal
set one=2
echo %one%
exit /b
> sample.bat
1
2
1
終了ステータスも返せます。
call :error
echo %errorlevel%
exit /b
:error
exit /b 1
> sample.bat
1
ただ、これの挙動がちょっと厄介で、shの$?
と同じように扱うとひどい目に遭います(遭いました)。
call :error
echo %errorlevel%
call :success
echo %errorlevel%
exit /b
:success
exit /b
:error
exit /b 1
> bad1.bat
1
1
これならどうだ!
call :error
echo %errorlevel%
call :success
echo %errorlevel%
exit /b
:success
set errorlevel=0
exit /b
:error
exit /b 1
> bad2.bat
1
0
一見大丈夫そうに見えますが、こうすると…。
call :error
echo %errorlevel%
call :success
echo %errorlevel%
call :error
echo %errorlevel%
exit /b
:success
set errorlevel=0
exit /b
:error
exit /b 1
> bad3.bat
1
0
0
ダメでした。
errorlevel
変数を自前で定義してしまうと、参照したときにそちらを指してしまって、exit
に渡した値が取れなくなります。
正解は案外簡単なことで…。
call :error
echo %errorlevel%
call :success
echo %errorlevel%
call :error
echo %errorlevel%
exit /b
:success
exit /b 0
:error
exit /b 1
> good.bat
1
0
1
exit
に明示的に0を渡してあげればよいのでした。
exit
に何も渡さないとerrorlevel
には何もセットしないので、前にセットされた終了ステータスが延々と引き継がれることになります。
サブルーチンを書くときには明示的に終了ステータスを書くようにした方が安全かと思います。
日時
date
とtime
に入ってます。
それぞれyyyy/mm/dd
とhh:mm:ss.SS
っぽいのでよしなにフォーマットして使いましょう。
echo %date%
echo %time%
> sample.bat
2017/07/28
17:30:18.91
IF
忙しい人のための早見表
対象 | 内容 | 演算子 |
---|---|---|
文字列 | 等しい | A == B |
等しくない | not A == B | |
数値 | 等しい | A equ B |
等しくない | A neq B | |
より大きい | A gtr B | |
より小さい | A lss B | |
以上 | A geq B | |
以下 | A leq B | |
ファイル・ディレクトリ | 存在する | exist A |
存在しない | exist A | |
変数 | 定義されている | defined A |
定義されていない | not defined A |
文字列比較
==
を使います。
if %1 == hoge (
echo This is hoge!
) else (
echo This is not hoge!
)
> sample.bat hoge
This is hoge!
> sample.bat huga
This is not hoge!
数値比較
色々あるのでよしなに使いましょう。
心なしか3文字って珍しい気がします(覚えづらい…)。
rem 等しい
if %1 equ 5 (
echo %1 is equal to 5!
)
rem 等しくない
if %1 neq 5 (
echo %1 is not equal to 5!
)
rem より大きい
if %1 gtr 5 (
echo %1 is bigger than 5!
)
rem より小さい
if %1 lss 5 (
echo %1 is less than 5!
)
rem 以上
if %1 geq 5 (
echo %1 is bigger than or equal to 5!
)
rem 以下
if %1 leq 5 (
echo %1 is less than or equal to 5!
)
> sample.bat 7
7 is not equal to 5!
7 is bigger than 5!
7 is bigger than or equal to 5!
存在確認
ファイル・ディレクトリ
exist
を使います。
if exist "%1" (
echo %1 exists!
) else (
echo %1 doesn't exist!
)
> cd
C:\Users\test
> dir
2017/08/08 08:00 hoge
2017/08/08 08:00 <DIR> huga
> sample.bat C:\Users\test\hoge
C:\Users\test\hoge exists!
> sample.bat C:\Users\test\huga
C:\Users\test\huga exists!
> sample.bat C:\Users\test\piyo
C:\Users\test\piyo doesn't exist!
ファイルとディレクトリの判定をしたい場合は後ろに\
を付けるといいようです。
ただし、必ず上手くいく訳でもないらしいのでご利用は計画的に。
if exist "%1" (
if exist "%1\" (
echo %1 is directory!
) else (
echo %1 is file!
)
) else (
echo %1 doesn't exist!
)
> dir
2017/08/08 08:00 hoge
2017/08/08 08:00 <DIR> huga
> sample.bat hoge
hoge is file!
変数
defined
を使います。
set hoge=hoge
if defined %1 (
echo %1 is defined!
) else (
echo %1 is not defined!
)
> sample.bat hoge
hoge is defined!