ASCII 文字だけの場合も Windows BAT ファイルを LF 改行コードで保存してはいけない
とある作業中に気付いた BAT ファイルの謎挙動について、書いておきます。
概要
Windows では、通常テキストファイルの改行コードには CR LF の 2バイトを使います。
プレーンテキストで記述されている BAT ファイルも、当然のことながら CR LF を改行コードに使います。
しかし、実際には改行コードを LF にしても、問題なく動くことが多いです。
よく問題となるのは、日本語を含む BAT ファイルの場合で、改行コード LF で日本語を含むバッチファイルの動作がおかしい件や改行コードがLFなバッチファイルなどで、実例が挙がっています。
しかし、最近、ASCII のみで構成された BAT ファイルであっても、改行コードが LF の場合に変な挙動を示すケースに出会いましたので、メモとして残しておきます。
結論としては、当たり前ですが、 CR LF で保存しましょう、ということ以外にないです。
最近は、テストの自動化などで、 Linux サーバーで動くソフトウェアから、 Windows 向けのテスト用 BAT ファイルを生成することもあるかと思いますが、注意しましょう。
再現方法
通常の動作
まずは、下記のような BAT ファイルを考えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 | @echo off goto label echo :label echo bad goto end :label echo good :end |
この BAT ファイルを実行すると、 3行目の goto label
で 10行目の :label
までジャンプするので、 11行目で "good" が出力されて終了します。
これは、改行コードが LF であっても CR LF であっても、どちらでも同じ結果になります。
奇妙な動作
続いて、下記のような BAT ファイルを考えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @echo off goto label 1234567890123456789012345678901234567890123456789 1234567890123456789012345678901234567890123456789 1234567890123456789012345678901234567890123456789 1234567890123456789012345678901234567890123456789 1234567890123456789012345678901234567890123456789 1234567890123456789012345678901234567890123456789 1234567890123456789012345678901234567890123456789 1234567890123456789012345678901234567890123456789 1234567890123456789012345678901234567890123456789 1234567890123456789012345678901234567890123456789 123456789012:label echo bad goto end :label echo good :end |
先の例と比べ、 goto label
でスキップされる部分に文字列を追加しただけなので、本質的な違いはありません。
そのため、実行すると "good" が出力されることが期待されます。
しかし、これを改行コードを LF として保存すると、 "bad" が出力されます。
BAT ファイルの謎の挙動
上述したことが起こるのは、 3行目の goto label
と 14行目末尾の :label
の間に 512 バイト (改行コード LF 含む) がある場合です。
より正確には、 512, 1024 など、512 の倍数が含まれている場合です。
この場合、どうやら 14行目末尾の :label
をラベルと誤認するようです。
改行コードが LF の場合、これ以外にも 3行目の goto label
と 19行目の :label
の間が 512バイト (改行コード LF 含む) 付近の場合、 :label
を見つけるのに失敗し、 goto label
に失敗します。
そもそも BAT ファイルには意味不明な挙動が多いですが、うっかり改行コードを LF にすると、さらに謎の挙動に悩まされることになるので、 Linux サーバーなどで BAT を生成する場合は、注意しましょう。
追記
ちなみに、「とある作業」とは、 Windows 上での Ruby のビルドのことです。
Ruby をソースコードからコンパイルする際に、この現象に出会いました。
Revision 47015 から Revision 47204 までの間、 Subversion の EOL の扱いに起因して、ダウンロードのやり方によっては win32\configure.bat が LF になってしまっていました。
私が指定したコマンドラインオプションの場合、今回の現象が偶然に起こっていました。
現象を単純化するのにとても疲れました。
改行コードそのものは Revision 47205 で修正していただけました。