• 追加された行はこの色です。
  • 削除された行はこの色です。
#author("2020-05-05T21:17:38+09:00","default:ryuichi","ryuichi")
* コマンドプロンプトなコマンドの出力が文字化けする [#h22b0840]
#author("2020-05-06T19:05:00+09:00","default:ryuichi","ryuichi")
* コマンドプロンプトなコマンドの入出力が文字化けする [#h22b0840]

** 前提 [#yc27212a]

** 普通に実行するだけなら文字化けしないが、パイプやファイルリダイレクトすると化ける [#l198d28c]
- PowerShellやWindowsの内部エンコーディングはUTF16
- 日本語WindowsだとコンソールのエンコーディングはSJISが既定になっている
- SJISとUTF16の変換は自動で行われ、PowerShellなコマンドだけを使うなら通常は問題ない
- しかし、コマンドプロンプトなコマンドは入出力が通常はSJISが想定されており、
- Linux由来のコマンドは入出力は通常はUTF8(またはUS-ASCII)が想定されている
- そのためコマンドレットと非PowerShellなコマンドを混ぜて使うとエンコーディングが違って文字化けすることがある
- これを解決するには、(1)非PowerShellなコマンドのエンコーディングを変更するか、(2)PowerShellのエンコーディングを変更するか、どちらか
- 非PowerShellなコマンドはエンコーディングが固定になっていることが多いので、ここでは(2)のPowerShellのエンコーディングを変更して問題を解決する
- なお、エンコーディングは入力と出力それぞれ考慮する必要がある

 PS> ipconfig.exe
** PowerShellの出力エンコーディングをSJISへ変更する [#m7a758c7]

 PS> Get-Date            (1)
 2020年5月6日 17:42:00
 
 Windows IP 構成
 
 イーサネット アダプター イーサネット:
 
    接続固有の DNS サフィックス . . . . .:
    IPv4 アドレス . . . . . . . . . . . .: 10.0.0.2
    サブネット マスク . . . . . . . . . .: 255.255.255.0
 PS> Get-Date | clip.exe (2)

- PowerShell上でipconfig.exeを実行すると、結果が日本語で表示される
- しかし、
- (1)は化けずにそのままコンソールに出力される
- (2)はclip.exeがUTF16に対応してないので、クリップボードには文字化けした文字列が入っている
- (ちなみにclip.exeは文字列をクリップボードにペーストすると昔からWindowsにあるコマンド)
- これを解決するには以下のようにする

 PS> ipconfig.exe > result.txt
 PS> ipconfig.exe | clip.exe
 PS> $OutputEncoding = [Text.Encoding]::Default  (1)
 PS> Get-Date | clip.exe

- のようにパイプやファイルリダイレクトすると化ける
- (1)のように$outputEncodingをSJISに指定するとPowerShellの出力がSJISになるので、clip.exeが文字列を読み込めるようになる

*** 補足 [#v4540451]

- なお、'''[Text.Encoding]::Default''' はSJISを表すが、以下のように '''[Text.Encoding]::GetEncoding('sjis')''' と指定してもいい
- その他のエンコーディング https://dobon.net/vb/dotnet/string/getencodingobject.html

 PS> [Text.Encoding]::GetEncoding('sjis')
 BodyName          : iso-2022-jp
 EncodingName      : 日本語 (シフト JIS)
 HeaderName        : iso-2022-jp
 WebName           : shift_jis
 WindowsCodePage   : 932
 IsBrowserDisplay  : True
 IsBrowserSave     : True
 IsMailNewsDisplay : True
 IsMailNewsSave    : True
 IsSingleByte      : False
 EncoderFallback   : System.Text.InternalEncoderBestFitFallback
 DecoderFallback   : System.Text.InternalDecoderBestFitFallback
 IsReadOnly        : True
 CodePage          : 932


#br

** PowerShellの入力エンコーディングを変更する [#o7f8e493]

 PS> $OutputEncoding = [Text.Encoding]::GetEncoding('utf-8')  (1)
 PS> gc .\1.json | jq.exe                                     (2)
 {
   "a": "日本語",
   "b": "英語"
 }

- (1)でPowerShellの出力をUTF8にしたので、(2)でjq.exeはJSONをパースできている。ここまではOK

 PS> gc .\1.json | jq.exe | Select-String "日本語"       (1)
                                                        (2)
 PS> [Console]::OutputEncoding = [Text.Encoding]::UTF8  (3)
 PS> gc .\1.json | jq.exe | Select-String "日本語"       (4)
  "a": "日本語",                                         (5)

- しかし、(1)のようにjq.exeの出力をPowerShellのSelect-Stringに渡すと、
- jq.exeはUTF8を出力しているのに、Select-Stringは入力をSJIS(からUTF16に変換する)に想定しているので、(2)のようにマッチに失敗する
- これを解決するには(3)のようにPowerShellの入力をUTF8にしてから、(4)のようにSelect-Stringに渡すと、(5)のようにマッチに成功する

** 補足:なんでこんな問題が起きるのか [#s4f29bde]

- Linuxのコマンドはパイプでつなげて使うが、パイプからは文字列が来る想定で設計されている
- 一方で、PowerShellのコマンドはパイプからオブジェクトが来る想定で設計されている
- したがって、PowerShellをPowerShellらしく使いたいなら、オブジェクトを処理できないコマンド(=Linux由来のコマンド)は使わない方がいい

** 参考 [#c7e34602]

https://ladybug.hatenadiary.org/entry/20111203/p1



トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS