バッチファイルメモ
いまどきコマンドプロンプトでバッチファイルを書く機会なんかないって? あるんだな、これが
文字コードとしてUTF-8を指定する
chcp 65001
今どきShift-JISでテキスト入力するやつなんかいねーのでほぼ必須
ちなみにchcpは言語モード(コードページ)を切り替えるコマンド。
本来の日本語モード(Shift-JIS)にするにはchcp 932を実行する。これによって一部の内部コマンドのメッセージが日本語で表示されるようになる。
コマンドの内容、コメントを非表示にする
@echo off
@を忘れるとこの行自体が表示されてしまう
コメント
rem "<コメント内容>"
ダブルクォーテーションで囲まないと(内部的な)出力時に変なところで改行されてエラーが出てくることがある。echo offを指定していたとしても出る。
'コメント内容' is not recognized as an internal or external command, operable program or batch file.
文字出力
echo <内容>
ダブルクォーテーションは不要。つけると出力内容にもついてくる。
例
code:bat
echo Hello World
結果
code:dos
Hello World
echoのみを実行すると、現在のECHO表示状態をメッセージで出力する。(出力結果が空になったときに出がちなので注意)
例
code:bat
echo
結果
code:dos
ECHO は <ON> です。
変数を設定する
set <変数名>=<内容>
code:bat
set FFMPEG_PATH=C:\ffmpeg\bin\ffmpeg.exe
=の間にスペースが入らないように注意する。
set a = somestringは動作しません。正しくはset a=somestring。
内容にもダブルクォーテーションは不要。入れた場合「ダブルクォーテーションを含んだ文字列」が代入されることになる。
内容を空にしたい場合はset <変数名>=
ちなみにset <変数名>のみだと変数名を頭文字にした環境変数一覧が表示されてしまう
code:dos
set t
TEMP=C:\Users\xxx\AppData\Local\Temp
TMP=C:\Users\xxx\AppData\Local\Temp
TERM_PROGRAM=vscode
...
変数を参照する
%<変数名>%
例
code:bat
set a=hello
echo %a%
結果
> hello
変数の即時展開と遅延展開
以下のスクリプトは意図した通りに動作しない
code:bat
@echo off
set a=foo
if "%a%" == "foo" (
set a=bar
echo %a%
)
結果
foo
原因は、変数がコマンド行単位で置き換えられているため。
まずsetでaにfooが入る。
次にif "%a%" == "foo" (set a=bar; echo %a%)(セミコロンは便宜上の改行コード)が解釈される時に、変数が置き換えられる(即時展開という)。すなわち、if "foo" == "foo" (set a=bar; echo foo)となる。
よってechoの結果はfooになる。
これを防ぐために「遅延展開」という機能がある。
スクリプトのできるだけ最初のほうにsetlocal enabledelayedexpansionと書く。
そして、変数は%ではなく!で囲む。
code:bat
@echo off
setlocal enabledelayedexpansion
set a=foo
if "%a%" == "foo" (
set a=bar
echo !a!
)
結果
bar
コマンドパラメータを参照する
%<数字>
オプションとかスイッチとか引数とか言ったりするアレ
%0がバッチファイル本体。%1が最初のパラメータ、以下%2、%3と続く
code:dos
@echo off
echo %1
echo %2
echo %3
echo %4
echo %5
code:dos
sample.bat Hello I am human.
Hello
I
am
human.
ECHO は <OFF> です。
この例だと%5は空なので最後にechoのみが実行されたことになる
コマンドパラメータの展開
以下はcall /?を実行したときのヘルプメッセージの一部である
code:dos
また、バッチ スクリプトの引数参照 (%0、%1 など) の展開は、次のように
変更されました:
%* バッチ スクリプト内では、すべての引数 (%1、%2、%3、%4、
%5 など) を参照します。
バッチ パラメーター (%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 と PATH は、他の有効な値で置き換えることができ
ます。%~ 構文は有効な引数の数によって区切られます。%~ 修飾子
は %* と同時には使用できません。
注意点
%~p1は「パスだけに展開します」が、ドライブ名を含まないことに注意。
%~p1はフォルダそのものが指定された場合、最後に区切り記号があればフォルダ自身を、なければその親を参照する。
例
"D:\Project\That\" -> \Project\That\
"D:\Project\That" -> \Project\
%~n1は「ファイル名だけに展開します」が、拡張子は含まれないことに注意。
コマンドパラメータの展開(例)
code:bat
set FFMPEG_PATH=C:\ffmpeg\bin\ffmpeg.exe
set INPUT_MOVIEFILE=%~1 <- 引数のフルパス
set TARGET_DIR=%~dp1 <- ドライブと親フォルダ
set TARGET_NAME=%~n1 <- ファイル名、拡張子なし
set OUTPUT_WAVFILE=%TARGET_DIR%%TARGET_NAME%.wav <- 同じフォルダ、ファイル名で拡張子のみ変更
%FFMPEG_PATH% -i "%INPUT_MOVIEFILE%" "%OUTPUT_WAVFILE%"
条件分岐
一行版
if <条件式> <真の時に実行されるコマンド>
if <条件式> <真の時に実行されるコマンド> else <偽の時に実行されるコマンド>
複数行版
code:bat
if <条件式> (
<真の時に実行されるコマンド>
...
)
code:bat
if <条件式> (
<真の時に実行されるコマンド>
...
) else (
<偽の時に実行されるコマンド>
...
)
条件式の例
table:文字列比較
a==b aとbの値は等しい
not a==b aとbの値は等しくない
%変数名%==文字列 変数の内容が文字列である(スペースが入らないように注意)
table:数値比較
a equ b aとbの値は等しい(a == b)
a neq b aとbの値は等しくない(a != b)
a gtr b aはbより大きい(a > b)
a lss b aはbより小さい(a < b)
a geq b aはb以上(a >= b)
a leq b aはb以下(a <= b)
ダブルクォーテーションが無い場合、数値っぽい文字列は数値として扱われるようだ
code:bat
if 9 gtr 10 (echo "9>10") else (echo "not 9<10")
"not 9<10"
文字列に対して数値比較しようとするとキャラクターコードの比較になるようだ。
code:dos
if "9" gtr "10" (echo "9>10") else (echo "not 9<10")
"9>10"
ANDやORなどの論理式は存在しない
ANDの表現のしかた
code:dos
if <条件式A> if <条件式B> (
<AかつB時の処理>
)
この式だとelseは挙動が変わってくるので基本的に使えない。
直後にelseを続けると「Aは真だがBは偽の時」のみ実行され、Aが偽の時実行されないことになる。
変数を使った解決策
code:dos
set STATUS=FALSE
if 条件A if 条件B set STATUS=TRUE
if %STATUS%==TRUE (
<AかつB時の処理>
) else (
<AではないもしくはBではない時の処理>
)
ORの表現
code:dos
if <条件式A> goto label
if <条件式B> goto label
<AでもBでもない時の処理>
...
label:
<AあるいはB時の処理>
変数を使った場合
code:dos
set STATUS=FALSE
if 条件A set STATUS=TRUE
if 条件B set STATUS=TRUE
if %STATUS%==TRUE (
<AあるいはB時の処理>
) else (
<AでもBでもない時の処理>
)
1番目のパラメータが指定されていないことを確認する
code:dos
if "%~1"=="" (
echo "ファイルを指定してください"
)
変数が定義されているか(いないか)調べる
if defined <変数名> <定義されている場合に実行されるコマンド>
if not defined <変数名> <定義されていない場合に実行されるコマンド>
ファイルやディレクトリが存在するかどうかを調べる
code:dos
if exist <ファイルパス> (
echo "あります"
) else (
echo "ありません"
)
終了する
exit /b
/bはバッチファイルを終了するオプション。単にexitのみだとコマンドプロンプト自体が終了してしまう