39

テキストを色付けするためのANSI エスケープ シーケンスを含む文字列を出力するプログラムを作成しました。しかし、スクリーンショットでわかるように、既定の Windows 10 コンソールでは期待どおりに動作しません。

プログラム出力は、エスケープ シーケンスが印刷された文字として表示されます。その文字列を変数またはパイプ経由で PowerShell にフィードすると、出力は意図したとおりに表示されます (赤いテキスト)。

回避策なしでプログラムが色付きのテキストを印刷するようにするにはどうすればよいですか?

ここに画像の説明を入力

これは私のプログラム ソース (Haskell) ですが、エスケープ シーケンスがどのように記述されているかを確認できるように、言語は関係ありません。

main = do
    let red = "\ESC[31m"
    let reset = "\ESC[39m"
    putStrLn $ red ++ "RED" ++ reset
4

3 に答える 3

88

Windows 10 のコンソール ウィンドウは 原則として VT (Virtual Terminal) / ANSI エスケープ シーケンスをサポートしていますが、サポートは既定でオフになっています。

次の 3 つのオプションがあります。

  • (a)この SU の回答で詳しく説明されているように、レジストリを介して、デフォルトでグローバルに永続的にサポートを有効にします。

    • つまり、レジストリ キーで、 DWORD 値を[HKEY_CURRENT_USER\Console]作成または設定します。VirtualTerminalLevel1
      • PowerShell から、次のようにプログラムでこれを行うことができます。
        Set-ItemProperty HKCU:\Console VirtualTerminalLevel -Type DWORD 1
      • からcmd.exe(PowerShell からも動作します):
        reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1
    • 変更を有効にするために、新しいコンソール ウィンドウを開きます。
    • 以下の注意事項を参照してください。
  • (b) Windows API 関数への呼び出しを使用して、そのプログラム (プロセス) のみに対して、プログラム内からサポートを有効にします。SetConsoleMode()

    • 以下の詳細を参照してください。
  • (c) PowerShell からのアドホックな回避策: 外部プログラムからの出力を にパイプしOut-Hostます。例えば、.\test.exe | Out-Host

    • 以下の詳細を参照してください。

Re (a):

レジストリベースのアプローチでは、どのシェル/プログラムが実行されているかに関係なく、常に VT サポートをグローバルに、つまりすべてのコンソール ウィンドウに対して有効にします。

  • 個々の実行可能ファイル/シェルは、必要に応じて方法 (b) を使用して、それ自体のサポートを無効にすることができます。

  • ただし、これは逆に、VT サポートを明示的に制御しないプログラムの出力は、VT シーケンスの解釈の対象になることを意味します。これは一般的には望ましいことですが、仮想的には、VT のようなシーケンスで誤って出力を生成するプログラムからの出力の誤解につながる可能性があります。

ノート:

  • のサブキーを介して、コンソール ウィンドウの設定を起動実行可能ファイル/ウィンドウ タイトルによってスコープできるメカニズムがあります、値はそこでサポートされていないようです。[HKEY_CURRENT_USR\Console]VirtualTerminalLevel

  • ただし、たとえそうであったとしても、ファイルには設定が組み込まれているため、ショートカットファイル ( ) (スタート メニューやタスク バーなどから)を介してコンソール ウィンドウを開くと、これらの設定が尊重されないため、堅牢なソリューションにはなりません。それら; これらの組み込み設定はGUI ダイアログを介して変更できますが、この記事の執筆時点では、設定はその GUI に表示されません。*.lnk*.lnkPropertiesVirtualTerminalLevel


(b) に関して:

ここに示すように、プログラム (プロセス) 内からSetConsoleMode()Windows API 関数を呼び出すことは、C# でも面倒であり (P/Invoke 宣言が必要なため)、オプションではない場合があります

  • Windows API の呼び出しがサポートされていない言語で記述されたプログラムの場合。

  • 変更できない既存の実行可能ファイルがある場合。

その場合、次に説明するオプション (c) (PowerShell から) が有効な場合があります。


再 (c):

PowerShell は、起動時に VT (仮想端末) サポート自動的に有効にします (Windows 10 の最近のリリースでは、これは Windows PowerShell と PowerShell Core の両方に適用されます) - ただし、これはPowerShellから呼び出される外部プログラムには適用されませ

ただし、PowerShell を介して外部プログラムの出力を中継すると、VT シーケンス認識ます。を使用するOut-Hostのが最も簡単な方法です(Write-Hostこれもうまくいきます):

.\test.exe | Out-Host

注:コンソールOut-Hostに出力する場合にのみ使用してください。対照的に、外部プログラムの出力をキャプチャしたい場合は、単に使用します$capturedOutput = .\test.exe

文字エンコーディングに関する警告: Windows PowerShell は既定で、レガシー システム ロケール (437米国英語システムなど) で定義され、 [console]::OutputEncoding. .NET コンソール プログラムはその設定を自動的に尊重しますが、別のエンコーディングを使用する (そして純粋な ASCII 出力 (7 ビット範囲) だけでなく) を使用する非 .NET プログラム (Python スクリプトなど) の場合は、(少なくとも一時的に) に割り当ててそのエンコーディングを指定します[console]::OutputEncoding。たとえば、UTF-8 の場合:
[console]::OutputEncoding = [Text.Encoding]::Utf8.
これは、VT シーケンスの回避策に必要なだけでなく、通常、PowerShell が非 ASCII 文字を正しく解釈するために必要であることに注意してください。

残念ながら、 PowerShell Core (v6+) は、v7.2 の時点でも OEM コード ページにデフォルト設定されていますが、BOM なしの UTF-8 にデフォルト設定されていることを考えると、これはバグと見なす必要があります

于 2018-08-04T01:20:53.393 に答える