Windows10のコードページについて調べてみた

## はじめに
Windows10のコードページについて、デフォルト(Shift_JIS)の`932`とUTF-8の`65001`との動作の違いが良くわからなかったので、調べてみたメモです。

## 結論
### `cmd`でコードページを`65001`にすると

* コマンドの実行結果が英語表示になる
* `type`してリダイレクトしても文字エンコードは変わらない
* PowerShell経由でShift_JISを表示させて、その結果をリダイレクトすると、BOMなしUTF-8に変換される

### PowerShellでは
* デフォルトの`932`では、外部コマンドの実行結果も日本語で統一される
* デフォルトで`65001`に切り替えると、外部コマンドの実行結果が英語表示になる
* コンソール出力をUTF-8にすると、外部コマンドの実行結果が英語表示になる

### WSLからWindowsのコマンドをパイプラインで使うと
* コードページが`65001`に切り替わって、その実行結果がWSLに渡される

## 試したこと
### コマンドシェル(cmd)
コマンドプロンプトとかコマンドウィンドウと呼ばれていますが、コマンドシェル(Command shell)というのが正式な名称[^1]のようです。


#### デフォルト
```
C:>chcp
現在のコード ページ: 932

C:>dir \ | findstr C:
 C:\ のディレクトリ

```

コマンドの実行結果が日本語で表示されます。

#### `chcp 65001`の後

```
Active code page: 65001

C:>dir \ | findstr C:
 Directory of C:\

```

コマンドの実行結果が英語になっています。
このままリダイレクト結果を確認してみます。

##### 入力ファイルの確認：テスト用ファイルを`type`
```
C:>type utf8.txt
これはUTF-8のテキストです。
C:>type utf8bom.txt
﻿これはBOM付きUTF-8のテキストです。
C:>type sjis.txt
SJIS�̃e�L�X�g�ł��B
C:>powershell -c cat sjis.txt
SJISのテキストです。

```

HTMLの中では実行結果が同じに見えるかもしれませんが、BOM付きのファイルを`type`すると、行頭に`･`(半角の中点)が表示されます。

##### テスト用ファイルを`type`してリダイレクト

```
C:>type utf8.txt >cmd_cp65001_type_utf8.txt

C:>type cmd_cp65001_type_utf8.txt
これはUTF-8のテキストです。�
C:>type utf8bom.txt >cmd_cp65001_type_utf8bom.txt

C:>type cmd_cp65001_type_utf8bom.txt
﻿これはBOM付きUTF-8のテキストです。
C:>type sjis.txt >cmd_cp65001_type_sjis.txt

C:>type cmd_cp65001_type_sjis.txt
SJIS�̃e�L�X�g�ł��B
C:>powershell -c cat cmd_cp65001_type_sjis.txt
SJISのテキストです。

```

リダイレクトしても、文字エンコードは変わりません。

##### テスト用ファイルをPowerShellで`cat`してリダイレクト
```
C:>powershell -c cat sjis.txt > cmd_cp65001_ps_cat_sjis.txt

C:>type cmd_cp65001_ps_cat_sjis.txt
SJISのテキストです。

C:>powershell -c "fhx cmd_cp65001_ps_cat_sjis.txt | %{$_.ToString()}"
00000000   53 4A 49 53 E3 81 AE E3 83 86 E3 82 AD E3 82 B9  SJISã®ãã­ã¹
00000010   E3 83 88 E3 81 A7 E3 81 99 E3 80 82 0D 0A        ãã§ãã..

```

Shift_JISがBOMなしUTF-8に変換されました。


### PowerShell

#### デフォルト

```
PS > chcp 932
現在のコード ページ: 932
PS > dir \ | oss | sls c:

    ディレクトリ: C:\


PS > [console]::OutputEncoding.CodePage
932
PS > cmd /c dir c:\ | sls c:

 c:\ のディレクトリ

```

#### デフォルトで`chcp 65001`の後
```
Active code page: 65001
PS > dir \ | oss | sls c:

    ディレクトリ: C:\


PS > [console]::OutputEncoding.CodePage
932
PS > cmd /c dir c:\ | sls c:

 Directory of c:\

```

外部コマンドでは、`chcp 65001`で設定したアクティブコードページが使われています。

#### utf-8環境

```
PS > chcp
現在のコード ページ: 932
PS > [console]::OutputEncoding = [Text.Encoding]::UTF8
PS > chcp
Active code page: 932
PS > dir \ | oss | sls c:

    ディレクトリ: C:\


PS > [console]::OutputEncoding.CodePage
65001
PS > cmd /c dir c:\ | sls c:

 Directory of c:\

```
外部コマンドでは、アクティブコードページではなく、`[console]::OutputEncoding.CodePage`の`65001`が使われています。

#### utf-8環境で`chcp 65001`の後

```
PS > chcp 65001
Active code page: 65001
PS > [console]::OutputEncoding.CodePage
65001
PS > dir \ | oss | sls c:

    ディレクトリ: C:\


PS > cmd /c dir c:\ | sls c:

 Directory of c:\


```

PowerShellの内部コマンドは、`chcp`で設定されるアクティブコードページには依存しない、という結果だと思います。

### WSLの`bash`

#### デフォルト

```
$echo $SHELL
/bin/bash
$chcp.com
現在のコード ページ: 932
$cmd.exe /c chcp
現在のコード ページ: 932
$cmd.exe /c chcp | cat
Active code page: 65001
```
表示させるだけとコードページはそのままですが、結果をパイプラインに渡すとコードページが`65001`に変更されてしまうようです。Shift_JISがパイプラインに渡されると、WSL側では普通に処理できないから、自動で切り替えているようです。

#### デフォルトで`chcp.com 65001`の後

```
Active code page: 65001
$chcp.com
現在のコード ページ: 932
$cmd.exe /c chcp
現在のコード ページ: 932
$cmd.exe /c chcp | cat
Active code page: 65001
```

コマンド実行後のメッセージは英語になりますが、実際の動作は何も変化していません。(当然の結果)

### 確認環境

* Windows10 Home 21H2
* PowerShell 5.1
* WSL1 Ubuntu 18.04
  
```
OS 名:                  Microsoft Windows 10 Home
OS バージョン:          10.0.19044 N/A ビルド 19044
PSVersion:              5.1.19041.1320
  NAME            STATE           VERSION
* Ubuntu-18.04    Running         1
```

## 参考


https://qiita.com/e4rfx/items/3772ecb58b6918ed5348


[^1]: [Windows のコマンド(コマンド シェルの概要)](https://docs.microsoft.com/ja-jp/windows-server/administration/windows-commands/windows-commands#command-shell-overview)