サブルーチンと戻り値

にメンテナンス済み

バッチファイルが大きくなってくると、同じ処理を何度も書くのは面倒ですし、バグの温床にもなります。そのような場合に役立つのがサブルーチン(疑似関数)です。

バッチファイルには他のプログラミング言語のような「関数定義」構文はありませんが、CALL :ラベル名 を使うことで関数に近い構造を実現できます。この記事では、サブルーチンの基本的な作り方から、引数の渡し方、数値・文字列の返し方まで順を追って解説します。

サブルーチンの基本構造

サブルーチンは次の要素で構成されます。

要素説明
CALL :ラベル名サブルーチンを呼び出す
:ラベル名サブルーチンの開始位置を示すラベル
EXIT /B 終了コードサブルーチンから呼び出し元へ戻る
GOTO :EOFEXIT /B 0 と同等。サブルーチンを終了する

メインの処理とサブルーチンを分けるために、メインコードの末尾に GOTO :EOF を置くのが重要なポイントです。これがないと、処理がそのままサブルーチンのコードへ流れ込んでしまいます。

@echo off
setlocal

CALL :GREET "田中"
CALL :GREET "山田"

GOTO :EOF

:GREET
echo こんにちは、%~1 さん!
EXIT /B 0
- □ ×
コマンド プロンプトのアイコン
コマンド プロンプト
Microsoft Windows [Version xx.x.xxxxx.xxx]
(c) 2026 Ribbit App Development All rights reserved.
 
C:\users\user>basic-sub.cmd
こんにちは、田中 さん!
こんにちは、山田 さん!
C:\users\user>
GOTO :EOF について

:EOF は特殊なラベルで、ファイルの末尾を意味します。EXIT /B 0 と同様にサブルーチンを終了しますが、終了コードを指定するには EXIT /B N を使います。メインコード末尾での使用はどちらでも構いません。

サブルーチンの配置場所

サブルーチンはファイルのどこに書いても動作しますが、メインの処理の後(GOTO :EOF の後)にまとめて記述する慣習が一般的です。コードの可読性が向上します。

サブルーチンへの引数の渡し方

CALL :ラベル名 引数1 引数2 ... のように、ラベル名の後に続けて引数を渡せます。サブルーチン内では %1、%2… でアクセスします。

記法意味
%11番目の引数(クォートを含む)
%~11番目の引数(前後のクォートを除去)
%22番目の引数
@echo off
setlocal

CALL :SHOW_INFO "山田" "東京" 30

GOTO :EOF

:SHOW_INFO
echo 名前: %~1
echo 都市: %~2
echo 年齢: %3
EXIT /B 0
- □ ×
コマンド プロンプトのアイコン
コマンド プロンプト
Microsoft Windows [Version xx.x.xxxxx.xxx]
(c) 2026 Ribbit App Development All rights reserved.
 
C:\users\user>args-demo.cmd
名前: 山田
都市: 東京
年齢: 30
C:\users\user>
おすすめ書籍※ 広告を含む場合があります
中小企業経営者のためのRPA入門 RPA導入を成功させる方法

中小企業経営者のためのRPA入門 RPA導入を成功させる方法

60分でわかる! AIエージェント 超入門

60分でわかる! AIエージェント 超入門

コマンドラインの黒い画面が怖いんです。

コマンドラインの黒い画面が怖いんです。

知識・才能ゼロでもらく~に月10万円稼ぐ! よくわかるAI副業超入門

知識・才能ゼロでもらく~に月10万円稼ぐ! よくわかるAI副業超入門

%~1 と %1 の違い

引数を "山田" のようにクォートで囲んで渡した場合、%1 では "山田"(クォート付き)、%~1 では 山田(クォートなし)になります。文字列を扱うときは %~1 を使う方が安全です。

数値の戻り値(ERRORLEVEL)

サブルーチンから数値を返すには、EXIT /B N で終了コード(N)を指定します。呼び出し元では %ERRORLEVEL% または IF ERRORLEVEL N で値を受け取ります。

慣習として、成功時は 0、エラー・失敗時は 1 以上の値を返します。

@echo off
setlocal

CALL :IS_EVEN 4
IF %ERRORLEVEL% EQU 0 (
    echo 4 は偶数です。
) ELSE (
    echo 4 は奇数です。
)

CALL :IS_EVEN 7
IF %ERRORLEVEL% EQU 0 (
    echo 7 は偶数です。
) ELSE (
    echo 7 は奇数です。
)

GOTO :EOF

:IS_EVEN
set /a CHECK=%1 %% 2
EXIT /B %CHECK%
- □ ×
コマンド プロンプトのアイコン
コマンド プロンプト
Microsoft Windows [Version xx.x.xxxxx.xxx]
(c) 2026 Ribbit App Development All rights reserved.
 
C:\users\user>numeric-return.cmd
4 は偶数です。
7 は奇数です。
C:\users\user>
%% の意味

set /a CHECK=%1 %% 2 の %% は、バッチファイル内で % 記号そのものを表すためのエスケープです。%1 %% 2 は「%1 を 2 で割った余り」を計算します。余りが 0 なら偶数、1 なら奇数です。

EXIT /B の終了コード

EXIT /B に数値を指定しない場合、その時点の ERRORLEVEL がそのまま返ります。意図しない値が返ることを防ぐため、EXIT /B 0 のように明示的に指定することを推奨します。

文字列の戻り値(endlocal & set トリック)

数値と違い、文字列の返却は少しトリッキーです。サブルーチン内で setlocal を使うと変数のスコープが閉じられるため、endlocal を呼んだ時点でサブルーチン内の変数はすべて消えてしまいます。

この問題を解決するのが endlocal & set 変数名=値 を 1 行にまとめるテクニックです。

なぜ 1 行にまとめると動くのか

コマンドプロンプトは 1 行を丸ごと解析してから実行します。endlocal & set RESULT=値 と書くと、set の右辺の値は endlocal が実行される前の状態で解析されます。つまり、サブルーチン内の変数の値が set の右辺に展開された後で endlocal が実行され、変数が呼び出し元のスコープに設定されるのです。

@echo off
setlocal

CALL :GET_GREETING "田中" RESULT
echo %RESULT%

GOTO :EOF

:GET_GREETING
setlocal
set NAME=%~1
set GREETING=こんにちは、%NAME% さん!
endlocal & set %~2=%GREETING%
EXIT /B 0
- □ ×
コマンド プロンプトのアイコン
コマンド プロンプト
Microsoft Windows [Version xx.x.xxxxx.xxx]
(c) 2026 Ribbit App Development All rights reserved.
 
C:\users\user>string-return.cmd
こんにちは、田中 さん!
C:\users\user>

このパターンでは、第 2 引数(%~2)に戻り値を格納する変数名を渡しています。呼び出し元が変数名を自由に指定できるため、汎用性が高まります。

固定変数名を使うパターン

変数名を引数で渡す代わりに、固定の変数名(例: RESULT)を使う方法もシンプルでよく使われます。

@echo off
setlocal

CALL :FORMAT_DATE
echo 整形された日付: %RESULT%

GOTO :EOF

:FORMAT_DATE
setlocal
set YEAR=%DATE:~0,4%
set MONTH=%DATE:~5,2%
set DAY=%DATE:~8,2%
set LOCAL_RESULT=%YEAR%%MONTH%%DAY%
endlocal & set RESULT=%LOCAL_RESULT%
EXIT /B 0
- □ ×
コマンド プロンプトのアイコン
コマンド プロンプト
Microsoft Windows [Version xx.x.xxxxx.xxx]
(c) 2026 Ribbit App Development All rights reserved.
 
C:\users\user>fixed-return.cmd
整形された日付: 20260424
C:\users\user>
1 行に書く必要がある

endlocal & set 変数名=値 は必ず 1 行に書く必要があります。2 行に分けると endlocal の時点でサブルーチン内の変数が消えてしまい、set の値が空になります。

複数の文字列を返す

endlocal & set %~2=%VAL1% & set %~3=%VAL2% のように、1 行に複数の set を並べることで複数の値を同時に返せます。引数で変数名を受け取るパターンと組み合わせると便利です。

実践例:ファイルの存在確認サブルーチン

ここまでの知識を組み合わせた実践的な例として、複数ファイルの存在を確認し、不足ファイルの数を返すサブルーチンを示します。

@echo off
setlocal

CALL :CHECK_FILES
IF %ERRORLEVEL% NEQ 0 (
    echo 必要なファイルが %ERRORLEVEL% 個不足しています。処理を中止します。
    GOTO :EOF
)
echo すべてのファイルが確認できました。処理を開始します。

GOTO :EOF

:CHECK_FILES
setlocal enabledelayedexpansion
set MISSING=0
for %%f in (config.ini data.csv template.xlsx) do (
    IF NOT EXIST "%%f" (
        echo 警告: %%f が見つかりません。
        set /a MISSING+=1
    )
)
endlocal & exit /b %MISSING%

config.ini が存在しない場合の実行例:

- □ ×
コマンド プロンプトのアイコン
コマンド プロンプト
Microsoft Windows [Version xx.x.xxxxx.xxx]
(c) 2026 Ribbit App Development All rights reserved.
 
C:\users\user>file-checker.cmd
警告: config.ini が見つかりません。
必要なファイルが 1 個不足しています。処理を中止します。
C:\users\user>

すべてのファイルが存在する場合:

- □ ×
コマンド プロンプトのアイコン
コマンド プロンプト
Microsoft Windows [Version xx.x.xxxxx.xxx]
(c) 2026 Ribbit App Development All rights reserved.
 
C:\users\user>file-checker.cmd
すべてのファイルが確認できました。処理を開始します。
C:\users\user>

まとめ

操作記法
サブルーチンの呼び出しCALL :ラベル名 引数1 引数2 ...
サブルーチンの終了EXIT /B 終了コード
引数の参照%1、%~1(クォート除去)
数値の返却EXIT /B N → 呼び出し元で %ERRORLEVEL% を参照
文字列の返却endlocal & set 変数名=値 を 1 行で実行
フォールスルー防止メインコード末尾に GOTO :EOF を配置

関連記事

練習問題

練習問題

サブルーチンから文字列の戻り値を返す際に使われるテクニックはどれですか?

回答がサーバーに送信されることはありません
#バッチファイル #サブルーチン #call #ERRORLEVEL #setlocal #コマンドプロンプト