LoginSignup
18
25

More than 5 years have passed since last update.

batノウハウ

Last updated at Posted at 2017-07-28

badノウハウならぬbatノウハウです。
忘れたことにやってくるbat作成のために良さそうなノウハウを見つけ次第追記します。
(何かあったら教えてくださいな)

echoさせない

行頭に@を付けても出力が抑制されますが、面倒なので文頭にこれを書いておきましょう。

sample.bat
@echo off

以降のサンプルコードは全て行頭にこれが書いてあるものと思ってください。

遅延環境変数を使う

色んな方が説明してくださってるので端折ります。
(特定単位で解釈してるからだとか)
忘れたころに使うとほぼ間違えなくはまります。

bad.bat
set count=0

for %%a in (1, 2, 3) do (
  set /a count+=1
  echo %count%
)
bad_result
> bad.bat
0
0
0
good.bat
rem 遅延環境変数を使えるようにする
setlocal enabledelayedexpansion

set count=0

for %%a in (1, 2, 3) do (
  set /a count+=1
  rem ↓遅延環境変数!
  echo !count!
)
good_result
> good.bat
1
2
3

どうでもいいですが、謎の魔法ではなく「enable delayed expansion」です。

引数

shで言うところの$1, $2, ... , $@, $*
ほぼ同じで、全部の引数を取りたいときは$*、各引数は$1, $2, ...です。

sample.bat
echo %1!
sample_result
> sample.bat hoge
hoge!

終了ステータス

shで言うところの$?
errorlevelに入ってます。

exitの引数として渡した値が終了ステータスになります。

sample.bat
rem bオプションを付けると呼び出し元プロセスを終了させない
rem (付けないと呼び出し元プロセスまで終了させられる)
exit /b 5
sample_result
> sample.bat

> echo %errorlevel%
5

関数っぽいもの(サブルーチン)

関数は存在しないそうです。
現代っ子プログラマーとしては非常につらいですね…。

ですが、ラベルをうまく利用すると関数っぽく処理を分割して書けます。

sample.bat
call :hello Hoge
call :hello Huga
call :hello Piyo

exit /b

:hello
echo Hello, %1!!
exit /b
sample_result
> sample.bat
Hello, Hoge!!
Hello, Huga!!
Hello, Piyo!!

setlocalも合わせて使うとなお良さそうですね。

sample.bat
set one=1

echo %one%
call :local
echo %one%

exit /b

:local
setlocal
set one=2
echo %one%
exit /b
sample_result
> sample.bat
1
2
1

終了ステータスも返せます。

sample.bat
call :error
echo %errorlevel%

exit /b

:error
exit /b 1
sample_result
> sample.bat
1

ただ、これの挙動がちょっと厄介で、shの$?と同じように扱うとひどい目に遭います(遭いました)。

bad1.bat
call :error
echo %errorlevel%
call :success
echo %errorlevel%

exit /b

:success
exit /b

:error
exit /b 1
bad1_result
> bad1.bat
1
1

これならどうだ!

bad2.bat
call :error
echo %errorlevel%
call :success
echo %errorlevel%

exit /b

:success
set errorlevel=0
exit /b

:error
exit /b 1
bad2_result
> bad2.bat
1
0

一見大丈夫そうに見えますが、こうすると…。

bad3.bat
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_result
> bad3.bat
1
0
0

ダメでした。
errorlevel変数を自前で定義してしまうと、参照したときにそちらを指してしまって、exitに渡した値が取れなくなります。

正解は案外簡単なことで…。

good.bat
call :error
echo %errorlevel%
call :success
echo %errorlevel%
call :error
echo %errorlevel%

exit /b

:success
exit /b 0

:error
exit /b 1
good_result
> good.bat
1
0
1

exitに明示的に0を渡してあげればよいのでした。

exitに何も渡さないとerrorlevelには何もセットしないので、前にセットされた終了ステータスが延々と引き継がれることになります。
サブルーチンを書くときには明示的に終了ステータスを書くようにした方が安全かと思います。

日時

datetimeに入ってます。
それぞれyyyy/mm/ddhh:mm:ss.SSっぽいのでよしなにフォーマットして使いましょう。

sample.bat
echo %date%
echo %time%
sample_result
> 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

文字列比較

==を使います。

sample.bat
if %1 == hoge (
  echo This is hoge!
) else (
  echo This is not hoge!
)
sample_result
> sample.bat hoge
This is hoge!
> sample.bat huga
This is not hoge!

数値比較

色々あるのでよしなに使いましょう。
心なしか3文字って珍しい気がします(覚えづらい…)。

sample.bat
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_result
> sample.bat 7
7 is not equal to 5!
7 is bigger than 5!
7 is bigger than or equal to 5!

存在確認

ファイル・ディレクトリ

existを使います。

sample.bat
if exist "%1" (
  echo %1 exists!
) else (
  echo %1 doesn't exist!
)
sample_result
> 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!

ファイルとディレクトリの判定をしたい場合は後ろに\を付けるといいようです。
ただし、必ず上手くいく訳でもないらしいのでご利用は計画的に。

sample.bat
if exist "%1" (
  if exist "%1\" (
    echo %1 is directory!
  ) else (
    echo %1 is file!
  )
) else (
  echo %1 doesn't exist!
)
sample_result
> dir
2017/08/08  08:00                   hoge
2017/08/08  08:00    <DIR>          huga
> sample.bat hoge
hoge is file!

変数

definedを使います。

sample.bat
set hoge=hoge
if defined %1 (
  echo %1 is defined!
) else (
  echo %1 is not defined!
)
sample_result
> sample.bat hoge
hoge is defined!

参考

18
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
25