まくまくWindowsノート
バッチファイルでコマンドライン引数を扱う
2019-10-02

コマンドライン引数の基本

バッチファイルの起動時にパラメータ(コマンドライン引数)を渡すには、下記のように空白で区切って値を入力します。

C:\> sample.bat AAA BBB CCC

バッチファイルの中でコマンドライン引数を参照するには、%1%2%3 といった特殊な変数を参照します。 %0 には、起動したバッチファイル名が格納されています(上記の例では sample.bat)。

下記のバッチファイルは、3 つのコマンドライン引数の値を表示します。 先頭の @echo off は、その後に実行するコマンドを画面上に表示しないようにするおまじないです。

sample.bat

@echo off
echo %1
echo %2
echo %3

実行例

C:\> sample AAA BBB CCC
AAA
BBB
CCC

指定するパラメータの数が足りない場合、echo コマンドがパラメータなしで実行されてしまうことに注意してください。

C:\> sample AAA
AAA
ECHO は <OFF> です。
ECHO は <OFF> です。

スペースを含むパラメータを渡す

パラメータとして渡したい文字列が空白を含んでいる場合は、その文字列全体をダブルクォーテーションで囲みます。

C:\> sample "AAA 1" "BBB 2" "CCC 3"
"AAA 1"
"BBB 2"
"CCC 3"

ただし、この場合は引用符も上記のようにそのまま出力されてしまうことに注意してください。 %1 と参照している部分を、%~1 という参照方法に変えると、引用符を削除して出力することができます。

sample.bat

@echo off
echo %~1
echo %~2
echo %~3

実行例

C:\> sample "AAA 1" "BBB 2" "CCC 3"
AAA 1
BBB 2
CCC 3

このような特殊な引数展開には、他にもいろいろな方法が用意されています。 コマンドシェル上で、call /? と実行すると、下記のようなヘルプを見ることができます。

バッチ パラメーター (%n) の置換は拡張されました。次のオプション構文
を使うことができます:

    %~1         - すべての引用句 (") を削除して、%1 を展開します。
    %~f1        - %1 を完全修飾パス名に展開します。
    %~d1        - %1 をドライブ文字だけに展開します。
    %~p1        - %1 をパスだけに展開します。
    %~n1        - %1 をファイル名だけに展開します。
    %~x1        - %1 をファイル拡張子だけに展開します。
    %~s1        - 展開されたパスは、短い名前だけを含みます。
    %~a1        - %1 をファイル属性に展開します。
    %~t1        - %1 をファイルの日付/時刻に展開します。
    %~z1        - %1 をファイルのサイズに展開します。
    %~$PATH:1   - PATH 環境変数に指定されているディレクトリを検索し、
                   最初に見つかった完全修飾名に %1 を展開します。
                   環境変数名が定義されていない場合、または
                   検索してもファイルが見つからなかった場合は、
                   この修飾子を指定すると空の文字列に展開されます。

修飾子を組み合わせて、複合結果を得ることもできます:

    %~dp1       - %1 をドライブ文字とパスだけに展開します。
    %~nx1       - %1 をファイル名と拡張子だけに展開します。
    %~dp$PATH:1 - PATH 環境変数に指定されているディレクトリを
                   検索して %1 を探し、最初に見つかったファイル
                   のドライブ文字とパスだけに展開します。
    %~ftza1     - %1 を DIR の出力行のように展開します。

コマンドライン引数が渡されたかどうか調べる

下記のようにすると、任意の位置のコマンドライン引数が渡されたか(渡されていないか)を調べることができます。

例: 1番目のパラメータが指定されていることを確認する

if not "%~1"=="" (
    echo %1
)

あるいは、neq を使って下記のようにも書けます。

if "%~1" neq "" (
    echo %1
)

neq は本来は数値を含むかもしれない文字列の比較のために使われる演算子ですが、ここでは空かどうかの比較をしているだけなので、うまく動作します。

例: 1番目のパラメータが指定されていないことを確認する

if "%~1"=="" (
    echo Need a parameter
    exit /b
)

条件式の中で、%1 と参照するのではなく、%~1 と参照しているのは、引用符で囲まれたパラメータを渡された場合に、シンタックスエラーになるのを防ぐためです。 まぁ、こう書くべきなのだと覚えておけば大丈夫です。

ちなみに、exit /b はコマンドシェルごと終了せずに、バッチファイルだけを終了する命令です。

コマンドライン引数の数を調べる

Linux のシェルスクリプトでは、$# でコマンドライン引数の数を調べることができますが、Windows のバッチファイルにはこのような仕組みはありません。 代わりに、n 個のパラメータが渡されたかどうかを調べるためには、n 番目のパラメータの値が空でないかを確認します。

例: 3 つのパラメータが渡されていなければバッチファイルを終了する

if "%~3"=="" (
    echo Need at least 3 parameters
    exit /b
)

コマンドライン引数をループ処理する

%* を使ったパラメータのループ処理

バッチファイルに渡されたすべてのパラメータは、%* という特殊な変数で、まとめて 1 つの文字列として参照することができます。 パラメータを 1 つずつ参照する方法では、%1%9 の 9 個までしか対応できないので、10 個以上のパラメータを使用する場合は、この %* を使用するしかありません(そんなケースはレアでしょうけど)。

下記の例では、for ループを使って、コマンドライン引数を 1 つずつ取り出しながらループ処理しています。

例: 渡されたパラメータを 1 つずつ echo する

@echo off
FOR %%a IN (%*) DO echo %%a

ここでは、ループ変数に %%a を使っていますが、%%a%%z の記号を使用することができます(小文字・大文字は区別されません)。

実行結果

C:\> sample AAA BBB CCC
AAA
BBB
CCC

空白を含むパラメータを渡したい場合にダブルクォーテーションで囲む必要があるのはこれまでと同様です。

C:\> sample "AAA BBB" CCC
"AAA BBB"
CCC

展開時に前後の引用符を削除するには、%%a と参照している部分を %%~a に変更します。

shift を使ったパラメータのループ処理

ちょっと特殊なやり方ですが、shift コマンドを使ってコマンドライン引数をループ処理する方法もあります。 shift コマンドを実行すると、%* に含まれている先頭の引数が削除(シフト)されます。 その結果、%1 が 2 番目のパラメータを参照するようになります。 これを繰り返すことで、すべてのコマンドライン引数をループ処理できます。

@echo off

:LOOP
if not "%~1"=="" (
    echo %~1
    shift
    goto LOOP
)

バッチファイルには while ループは存在しないので、仕方なく goto を使って LOOP ラベルへジャンプしています。 気持ち悪いコードですね。 ループ処理はできるだけ FOR を使って記述しましょう。

(応用)コマンドライン引数が足りない場合に Usage 表示する

下記のバッチファイルは、パラメータが指定されていない場合に、使用方法 (Usage) を出力して終了します。 テンプレートとしてお使いください。

hello.bat

@echo off
setlocal

if "%~1"=="" (goto USAGE)

echo Hello, %~1.
echo I am Maku.

exit /b
:USAGE
    echo Usage: sample YOUR_NAME

実行例

C:\> hello
Usage: sample YOUR_NAME

C:\> hello Jack
Hello, Jack.
I am Maku.

(応用)コマンドライン引数が省略された場合にデフォルト値を使用する

下記のバッチファイルは、パラメータが省略された場合に、デフォルトの値(ここでは 100)を使って動作します。 テンプレートとしてお使いください。

age.bat

@echo off
setlocal

set AGE=%~1
if "%AGE%"=="" (set AGE=100)

echo You are %AGE% years old

実行例

C:\> age
You are 100 years old

C:\> age 14
You are 14 years old
2019-10-02