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

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 で修正していただけました。