Chapter 20

たまーに必要になる LF → CRLF 改行コード変換

zetamatta
zetamatta
2021.06.17に更新

Windowsで閉じた仕事をしている分には改行コード変換など滅多に必要にならないのですが、たまに UNIX系ツールを使う時、LF(U+0A) しか出力しないものもあって困ります。

たとえば git で改変のあったファイルだけ処理したい時:

for /F "tokens=2" %%I in ('git status -s ^| findstr /R ".M.*\.md$" ') do echo %%I

など書いてみますが、最初のものしか処理されません。理由は git status -s の出力が LF になっているためのようです。

$ git status -s
 M Makefile
 M main.go
?? make.bat
$ git status -s | binview.exe
00000000 20 4D 20 4D 61 6B 65 66 69 6C 65 0A 20 4D 20 6D  M Makefile. M m
00000010 61 69 6E 2E 67 6F 0A 3F 3F 20 6D 61 6B 65 2E 62 ain.go.?? make.b
00000020 61 74 0A                                        at.

nkf や dos2unix などサードパーティツールを使えば簡単に LF(U+0A) → CRLF(U+0D U+0A) 変換ができますが、そうするとバッチファイルの使用条件が増えてしまいます。できれば OS の標準コマンドだけで変換したいものです。何かないかな…

$ git status -s | more.com | binview.exe
00000000 20 4D 20 4D 61 6B 65 66 69 6C 65 0D 0A 20 4D 20  M Makefile.. M
00000010 6D 61 69 6E 2E 67 6F 0D 0A 3F 3F 20 6D 61 6B 65 main.go..?? make
00000020 2E 62 61 74 0D 0A 0D 0A                         .bat....

more を通すと LF が CRLF に変換されるようです。しかしながら、more.com はページ境界にプロンプトを挟む可能性があります。どないでしょう…

$ gawk "BEGIN{ for(i=0;i<100;i++){ print i } }" | more.com | binview.exe
00000000 30 0D 0A 31 0D 0A 32 0D 0A 33 0D 0A 34 0D 0A 35 0..1..2..3..4..5
00000010 0D 0A 36 0D 0A 37 0D 0A 38 0D 0A 39 0D 0A 31 30 ..6..7..8..9..10
00000020 0D 0A 31 31 0D 0A 31 32 0D 0A 31 33 0D 0A 31 34 ..11..12..13..14
00000030 0D 0A 31 35 0D 0A 31 36 0D 0A 31 37 0D 0A 31 38 ..15..16..17..18
00000040 0D 0A 31 39 0D 0A 32 30 0D 0A 32 31 0D 0A 32 32 ..19..20..21..22
00000050 0D 0A 32 33 0D 0A 32 34 0D 0A 32 35 0D 0A 32 36 ..23..24..25..26
00000060 0D 0A 32 37 0D 0A 32 38 0D 0A 32 39 0D 0A 33 30 ..27..28..29..30
00000070 0D 0A 33 31 0D 0A 33 32 0D 0A 33 33 0D 0A 33 34 ..31..32..33..34
00000080 0D 0A 33 35 0D 0A 33 36 0D 0A 33 37 0D 0A 33 38 ..35..36..37..38
00000090 0D 0A 33 39 0D 0A 34 30 0D 0A 34 31 0D 0A 34 32 ..39..40..41..42
000000A0 0D 0A 34 33 0D 0A 34 34 0D 0A 34 35 0D 0A 34 36 ..43..44..45..46
000000B0 0D 0A 34 37 0D 0A 34 38 0D 0A 34 39 0D 0A 35 30 ..47..48..49..50
000000C0 0D 0A 35 31 0D 0A 35 32 0D 0A 35 33 0D 0A 35 34 ..51..52..53..54
000000D0 0D 0A 35 35 0D 0A 35 36 0D 0A 35 37 0D 0A 35 38 ..55..56..57..58
000000E0 0D 0A 35 39 0D 0A 36 30 0D 0A 36 31 0D 0A 36 32 ..59..60..61..62
000000F0 0D 0A 36 33 0D 0A 36 34 0D 0A 36 35 0D 0A 36 36 ..63..64..65..66
00000100 0D 0A 36 37 0D 0A 36 38 0D 0A 36 39 0D 0A 37 30 ..67..68..69..70
00000110 0D 0A 37 31 0D 0A 37 32 0D 0A 37 33 0D 0A 37 34 ..71..72..73..74
00000120 0D 0A 37 35 0D 0A 37 36 0D 0A 37 37 0D 0A 37 38 ..75..76..77..78
00000130 0D 0A 37 39 0D 0A 38 30 0D 0A 38 31 0D 0A 38 32 ..79..80..81..82
00000140 0D 0A 38 33 0D 0A 38 34 0D 0A 38 35 0D 0A 38 36 ..83..84..85..86
00000150 0D 0A 38 37 0D 0A 38 38 0D 0A 38 39 0D 0A 39 30 ..87..88..89..90
00000160 0D 0A 39 31 0D 0A 39 32 0D 0A 39 33 0D 0A 39 34 ..91..92..93..94
00000170 0D 0A 39 35 0D 0A 39 36 0D 0A 39 37 0D 0A 39 38 ..95..96..97..98
00000180 0D 0A 39 39 0D 0A 0D 0A                         ..99....

どうやら、標準出力がリダイレクトされている時はプロンプトを出さないようです。標準エラー出力にも出ていません。これならば改行コードフィルターとして問題なさそうです。先の例も:

for /F "tokens=2" %%I in ('git status -s ^| more.com ^| findstr /R ".M.*\.md$" ') do echo %%I

で期待どおり動きました。よしよし