初めてバッチファイルを作成する中で、同じ処理を何度も実行する必要があり、他の言語でいうところの関数を使いたいと思い調べたのでメモしておきます。
Windowsバッチにおける関数(的な存在)
1.基本的な使い方
Windowsバッチで関数的なものを使用するためには、正確には「ラベル」というもの使用します。以下のようにラベルを定義し、
:ラベル名
実行したい処理を書く
「call :ラベル名」と呼び出すことでラベルの場所に処理がジャンプします。
call :OHAYO
echo KONNITIHA
exit /b
:OHAYO
echo OHAYO
exit /b
実行結果
OHAYO
KONNITIHA
処理の流れは以下の通りです。ラベルで関数的な使い方ができていることがわかります。
①処理開始
②OHAYOラベルを呼び出す
③OHAYOを出力
④exit /bにぶち当たるので呼び出し元に実行権が返る
⑤②の次の処理のKONNITIHA出力処理を実行
⑥exit /bにぶち当たるので処理終了
ただし「call :ラベル」はあくまでラベルの場所に処理が移るだけなので、ラベル内処理の最後にexit /bを書かないとそのまま処理が下に抜けていってしまうため注意が必要です。(上で「ジャンプ」を強調したのはこのためです)
call :OHAYO
echo KONNITIHA
exit /b
:OHAYO
echo OHAYO
REM exit /bがないので下のKONBANHAラベルが実行されてしまう
:KONBANHA
echo KONBANHA
実行結果
OHAYO
KONBANHA
KONNITIHA
2.引数の渡し方
関数には当然引数も渡したくなると思います。
引数を渡す時は、ラベル名の後ろに書くだけです。
受け取る時は、ラベル内で「%1」、「%2」...を使用します。(数字は引数を渡す順番に対応します)
set name=Qiita
echo OHAYO %name%
echo KONNITIHA
exit /b
:OHAYO
set name=%1
echo %name% OHAYO
exit /b
実行結果
Qiita OHAYO
KONNITIHA
3.戻り値の受け取り方
関数なので戻り値も受け取りたくなると思います。
ラベル内のexit /b の後ろに戻り値を書き、呼び出し元のcall文の次で%errorlevel%を受け取ってあげると戻り値を取得できます。
@echo off
set number1=1
set number2=2
call :TASHIZAN %number1% %number2%
set result=%errorlevel%
echo result is %result%
exit /b
:TASHIZAN
set number1=%1
set number2=%2
set /a result=%number1%+%number2%
exit /b %result%
実行結果
result is 3
errorlevelという名前から、本来は以下のように処理の成功/失敗を判定する用途のようですが、関数の戻り値的に利用することができます。
@echo off
call :CHECK
set result=%errorlevel%
REM 戻り値で成功/失敗を判定して処理を分岐する
if %errorlevel%==1 (
echo error
exit /b
)
if %errorlevel%==0 (
echo success
)
exit /b
:CHECK
set file=%~dp0file1
if not exist %file% (
REM ファイルが存在しなかったら1を返す
exit /b 1
) else (
REM ファイルが存在したら0を返す
exit /b 0
)
注意
errorlevelに設定できる値について
errorlevelに設定できるのは数値だけで、文字列を設定することはできません。以下例では:GET_FULL_NAMEに姓名を渡してフルネームを取得しようとしていますが、errorlevelとして0が返ってきてしまいます。
@echo off
set familyName=Qiita
set firstName=Taro
call :GET_FULL_NAME %familyName% %firstName%
set fullName=%errorlevel%
echo fullName is %fullName%
exit /b
:GET_FULL_NAME
set fullName=%1 %2
REM フルネームを返したいが、、、
exit /b %fullName%
実行結果
→0が出力されています。
fullName is 0
処理結果で文字列がほしい時は、errorlevelとして返すのではなくラベル処理内で変数に設定してあげる等の対応が必要になります。
@echo off
set familyName=Qiita
set firstName=Taro
call :GET_FULL_NAME %familyName% %firstName%
echo fullName is %fullName%
exit /b
:GET_FULL_NAME
REM ここで変数fullNameに設定する
set fullName=%1 %2
REM exit /bの後ろには何も書かない
exit /b
実行結果
fullName is Qiita Taro
補足 「call: ラベル名」と「goto :ラベル名」の違いについて
ラベルを呼び出す方法には、「call」の他に「goto」もあります。両者の違いは呼び出し元に処理が戻るか戻らないかです。「goto」を使用するとジャンプ先に行ったっきりで呼び出し元に戻ってきません。
先ほどのバッチのcallをgotoに変えて実行すると何も出力がされません。
@echo off
set familyName=Qiita
set firstName=Taro
REM callをgotoに変更
goto :GET_FULL_NAME %familyName% %firstName%
echo fullName is %fullName%
exit /b
:GET_FULL_NAME
set fullName=%1 %2
exit /b
実行結果
→呼び出し元に処理が戻らず「echo fullName is ~」が実行されないので、何も出力されない