LoginSignup
3
3

More than 1 year has passed since last update.

PowerShellからパイプラインで外部に繋ぐための文字エンコード設定

Posted at

はじめに

PowerShellでのテキスト処理が、やはり簡単ではないことが多いと感じてきました。PowerShellから外部コマンドやwslに渡すために試したことをメモにまとめました。

結論

  • 外部コマンドに渡す場合は$OutputEncoding[console]::OutputEncodingに揃える
    • $OutputEncoding = [console]::OutputEncoding
  • wslに渡す場合は$OutputEncodingutf-8にする
    • $OutputEncoding = [System.Text.Encoding]::UTF8

試したこと

デフォルトでの動作

PS > ls \ | oss | sls c:

    ディレクトリ: C:\


PS > ls \ | findstr C:
    ??????: C:\
PS > ls \ | wsl grep C:
    ??????: C:\

7bit分しか渡されていないようです。
これは、$PSDefaultParameterValuesを変更しても変わりませんでした。

調べると、下記の記事がヒットしました。

$OutputEncodingの設定が必要ということがわかりました。

ドキュメントを良く読む

このセクションの最後の部分に以下のように書いてありました。

自動変数は $OutputEncoding 、外部プログラムとの通信に PowerShell が使用するエンコードに影響します。

ということで、$OutputEncodingを調べるとデフォルトではus-asciiになっていました。

PS > $OutputEncoding.WebName
us-ascii

$OutputEncodingについて、ドキュメントを見てみましょう。
* 参考:基本設定変数について - PowerShell ($OutputEncoding)

findstr.exeに渡す場合は、以下のように設定する必要があると書かれています。

PowerShell でコマンドを機能させるには、 の値を コンソールの $OutputEncoding OutputEncoding プロパティの値に設定します。これは、Windows に対して選択されたロケールに基づいて行います。

$OutputEncoding = [console]::OutputEncoding

これで何が設定されるかを実際に調べてみると、

PS > [console]::OutputEncoding


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


こうなっていました。コンソールの出力と、$OutputEncodingとが一致していないと文字化けするということですね。
$OutputEncodingに何が設定出来るのかを知るために、以下のリンクを辿ってみました。

既定値: ASCIIEncodingオブジェクト。

各プロパティの継承元を追ってみます。

(継承元 Encoding)

この中に一覧表があり、ここで「.NET Framework サポート」のチェックがあるものが設定可能ということがわかりました。

この表の下に、以下のメソッドを見つけました。

GetEncoding(Int32) GetEncoding(String)

コードページかエンコードの名前を用いて文字エンコードが指定できるということですね。
クラスがSystem.Text.Encodingということもわかったので、試してみます。

PS > [System.Text.Encoding]::GetEncoding(65001).webname
utf-8
PS > [System.Text.Encoding]::GetEncoding('utf-8').webname
utf-8

他にも指定する方法がないか、調べてみました。

PS > [System.Text.Encoding] | get-member -static


   TypeName: System.Text.Encoding

Name             MemberType Definition
----             ---------- ----------
Convert          Method     static byte[] Convert(System.Text.Encoding srcEncoding, System.Text.Encoding dstEncoding...
Equals           Method     static bool Equals(System.Object objA, System.Object objB)
GetEncoding      Method     static System.Text.Encoding GetEncoding(int codepage), static System.Text.Encoding GetEn...
GetEncodings     Method     static System.Text.EncodingInfo[] GetEncodings()
ReferenceEquals  Method     static bool ReferenceEquals(System.Object objA, System.Object objB)
RegisterProvider Method     static void RegisterProvider(System.Text.EncodingProvider provider)
ASCII            Property   static System.Text.Encoding ASCII {get;}
BigEndianUnicode Property   static System.Text.Encoding BigEndianUnicode {get;}
Default          Property   static System.Text.Encoding Default {get;}
Unicode          Property   static System.Text.Encoding Unicode {get;}
UTF32            Property   static System.Text.Encoding UTF32 {get;}
UTF7             Property   static System.Text.Encoding UTF7 {get;}
UTF8             Property   static System.Text.Encoding UTF8 {get;}


UTF8DefaultASCIIのプロパティが使えそうです。

PS > [System.Text.Encoding]::UTF8.WebName
utf-8
PS > [System.Text.Encoding]::Default.WebName
shift_jis
PS > [System.Text.Encoding]::ASCII.WebName
us-ascii

これで、必要な文字エンコードを直接指定することができるようになりました。

期待通りの動作

PS > $OutputEncoding = [console]::OutputEncoding
PS > ls \ | findstr C:
    ディレクトリ: C:\
PS > $OutputEncoding = [System.Text.Encoding]::UTF8
PS > ls \ | wsl grep C:
    ディレクトリ: C:\

$OutputEncodingを固定して使う場合は、$profileファイルに書き込んでおくと便利です。
* 参考:$profileファイルの編集手順

確認環境

  • Windows 10 Home 21H2
PS > (gi function:ver).definition
(systeminfo | ?{$_.Contains("OS")})[0,1];($PSVersionTable | oss)[3].trim() -replace ' +',":`t`t";(wsl -l)[3].Split()[0]
PS > ver
OS 名:                  Microsoft Windows 10 Home
OS バージョン:          10.0.19044 N/A ビルド 19044
PSVersion:              5.1.19041.1320
Ubuntu-18.04

(wsl -l)の文字化けは調査中(上記は文字化け結果を利用したもの)

参考

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3