SyntaxHighlighter

2014年8月17日日曜日

ASCII 文字だけの場合も Windows BAT ファイルを LF 改行コードで保存してはいけない

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 ファイルを考えます。

この BAT ファイルを実行すると、 3行目の goto label で 10行目の :label までジャンプするので、 11行目で "good" が出力されて終了します。

これは、改行コードが LF であっても CR LF であっても、どちらでも同じ結果になります。

奇妙な動作

続いて、下記のような BAT ファイルを考えます。

先の例と比べ、 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 で修正していただけました。

0 件のコメント:

コメントを投稿