DOSの引数って面倒くさい
この記事を書いている中で、PHPやComposerをうまいこと複数バージョン対応にしたくて 「そうだ、PATHが通っているところにショートカットっぽく実行ファイルを置けばいいんだ」と気付き、試してみた。
例えば、以下の環境・要件のとき
- 環境
-
php
でPHP8.0のパスが通っていてphp7
でPHP7.4を実行したい - php8.1は
D:\xampp\php\php.exe
に存在する(PATHが通っている) - php7.4は
D:\xampp\php7\php.exe
に存在する(PATHは通っていない) -
php -v
はPHP8.1が表示されるようになっている
-
- 要件
-
php7 -v
はPHP7.4が表示されるようにする(引数が1つ) -
php7 コマンドの引数の数は予測できないがすべて利用できるようにしなければならない
-
php7 引数1 引数2 ... 引数X
が使えるようにする - 引数は10個以上の可能性もある
-
-
まずは1を解決(引数が1個)
これは簡単、 D:\xampp\php\
に php7.bat
を配置し、php7.4を実行してやれば良い
@echo off
echo execute: D:\xampp\php7\php.exe %1
D:\xampp\php7\php.exe %1
2行目は実運用では不要だが、何を実行したかわかるようにechoしている。
以下、実行結果
> php7 -v
execute: D:\xampp\php7\php.exe -v
PHP 7.4.22 (cli) (built: Jul 28 2021 09:44:30) ( ZTS Visual C++ 2017 x64 )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
間違いなくphp7.4が実行されている。
DOSの引数は10個までしか扱えない?
たとえば、以下のコマンドを実行する場合
> php7 a b c d e f g h i j k l
こうすれば行けそうな気がするが
@echo off
echo execute: D:\xampp\php81\php.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12
D:\xampp\php7\php.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12
こう実行されてしまう
> php7 a b c d e f g h i j k l
execute: D:\xampp\php7\php.exe a b c d e f g h i a0 a1 a2
a0 a1 a2
ってなんだ?と思うが、これは、%n
のn部分に2文字が利用できないため。
つまり '%10' は 引数%1 + 数字の0
という扱いになってしまう。
しかも引数が少ないと
> php7 a b c
execute: D:\xampp\php7\php.exe a b c a0 a1 a2
こうなってしまうため、要件2の 引数の数は予測できない にマッチしない。
(10個以内ならマッチするが、無駄な半角スペースが入る)
そこで、下記記事のようにshift
を使うことで回避ができる。
つまり、こうすれば良い(前者の記事から引用して改変している)
@echo off
set count=1
set argv=
:loop
if "%1"=="" goto :confirm
set argv=%argv% %1%
set /a count+=1
shift
goto loop
:confirm
echo execute: D:\xampp\php81\php.exe%argv%
D:\xampp\php7\php.exe%argv%
これで php7 -S localhost:8000
や php7 artisan breeze:install react
のようなケースにも対応できる。
注意
laravelはcomposer側に工夫が必要なので、引数が使えるというだけで、このままで正常動作するわけではない。
引数にワイルドカードが使えるじゃん!
ここまででひとまず完成ではあるが、同じことをcomposerで設定しようとしたところ、composer.bat
に以下のような記述があった。
@echo OFF
:: in case DelayedExpansion is on and a path contains !
setlocal DISABLEDELAYEDEXPANSION
php "%~dp0composer.phar" %*
なんと、%*
が使えるではないか
「DOS 引数」でググっても基本的には上記記事のようなshiftで対応するものばかりなで、ソースが見つけられなかった。
唯一見つけた以下の記事を参照すると
バッチ パラメータ %* は、バッチ ファイルに渡される %0 を除くすべての引数を参照するワイルドカードです。
と記載されている(%0
については後述)。
この記事が2008年なので、WindowsXP ~ 7の間くらいで採用されたか、NT系の標準仕様なのかもしれない。
早速、試してみよう
@echo off
echo execute: D:\xampp\php81\php.exe %*
D:\xampp\php7\php.exe %*
> php7 a b c d e f g h j k l
execute: D:\xampp\php7\php.exe a b c d e f g h j k l
なんとたったの3行で実行できた。
試しにちゃんと実行できる引数で試してみる。
> php7 -v
execute: D:\xampp\php7\php.exe -v
PHP 7.4.22 (cli) (built: Jul 28 2021 09:44:30) ( ZTS Visual C++ 2017 x64 )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
> php7 -S localhost:8000
execute: D:\xampp\php7\php.exe -S localhost:8000
[Fri Sep 9 11:25:56 2022] PHP 7.4.22 Development Server (http://localhost:8000) started
完璧!
composerさん、大切な気付きをくれてありがとう。
shift
を駆使している皆さん、早く気づいて!
番外:引数9個しか使えてなくない?(%0について)
説明を省いたが %0
が存在し、コマンド(batファイル)の(フル)パスが引数となる。
本件の場合は D:\xampp\php\php7.bat
になる。
使わないので省略しているがこれで引数の合計が10個となる。