web-dev-qa-db-fra.com

Sortie de texte en couleur dans la console PowerShell à l'aide des codes ANSI / VT100

J'ai écrit un programme qui imprime une chaîne, qui contient séquences d'échappement ANSI pour colorer le texte. Mais cela ne fonctionne pas comme prévu dans la console Windows 10 par défaut, comme vous pouvez le voir sur la capture d'écran.

La sortie du programme apparaît avec les séquences d'échappement sous forme de caractères imprimés. Si j'introduis cette chaîne dans PowerShell via une variable ou une tuyauterie, la sortie apparaît comme prévu (texte rouge).

Comment puis-je obtenir que le programme imprime du texte en couleur sans aucune solution?

enter image description here

Ceci est ma source de programme (Haskell) - mais le langage n'est pas pertinent, juste pour que vous puissiez voir comment les séquences d'échappement sont écrites.

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

Alors que les fenêtres de console dans Windows 10 prennent en charge les séquences d'échappement VT (Virtual Terminal)/ANSI en principe, le support est désactivé OFF par défaut.

Vous avez trois options:

  • (a) Activer le support globalement par défaut, de façon persistante, via le registre, comme détaillé dans this Réponse S .

    • En bref: dans la clé de registre [HKEY_CURRENT_USER\Console], Créez ou définissez la valeur DWORD VirtualTerminalLevel sur 1
      • À partir de PowerShell, vous pouvez le faire par programmation comme suit:
        Set-ItemProperty HKCU:\Console VirtualTerminalLevel -Type DWORD 1
      • Depuis cmd.exe (Fonctionne également depuis PowerShell):
        reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1
    • Ouvrez une nouvelle fenêtre de console pour que les modifications prennent effet.
    • Voir les mises en garde ci-dessous.
  • (b) Activez le support depuis l'intérieur de votre programme, pour ce programme (processus) uniquement, avec un appel à la SetConsoleMode() Fonction API Windows.

    • Voir les détails ci-dessous.
  • (c) Solution de contournement ad-hoc, de PowerShell: redirige la sortie des programmes externes vers Out-Host ; par exemple, .\test.exe | Out-Host

    • Voir les détails ci-dessous.

Concernant (a):

L'approche basée sur le registre active invariablement le support VT globalement, c'est-à-dire pour all les fenêtres de console , indépendamment de ce que Shell/programme y exécute:

  • Les exécutables/shells individuels peuvent toujours désactiver le support d'eux-mêmes, si vous le souhaitez, en utilisant la méthode (b).

  • Inversement, cependant, cela signifie que la sortie de tout programme qui ne contrôle pas explicitement le support VT sera sujette à l'interprétation des séquences VT; bien que cela soit généralement souhaitable, cela pourrait hypothétiquement conduire à une mauvaise interprétation de la sortie de programmes qui accidentellement produisent une sortie avec des séquences de type VT.

Remarque:

  • Alors qu'il existe est un mécanisme qui permet aux paramètres de la fenêtre de la console d'être étendus par le titre de l'exécutable/de la fenêtre de démarrage, via sous-clés de [HKEY_CURRENT_USR\Console], Le VirtualTerminalLevel la valeur ne semble pas y être prise en charge.

  • Même si c'était le cas, cependant, ce ne serait pas une solution robuste, car ouvrir une fenêtre de console via un fichier raccourci (*.lnk ) (par exemple à partir du menu Démarrer ou de la barre des tâches) ne respecterait pas ces paramètres, car les fichiers *.lnk ont des paramètres intégrés; bien que vous puissiez modifier ces paramètres intégrés via la boîte de dialogue de l'interface graphique Properties, à ce jour, le paramètre VirtualTerminalLevel n'est pas indiqué dans cette interface graphique.


Concernant (b):

L'appel de la fonction SetConsoleMode() API Windows depuis l'intérieur du programme (processus), comme décrit ici , est fastidieux même en C # (en raison de la nécessité d'un P/Invoke declaration), et peut ne pas être une option :

  • pour les programmes écrits dans des langues à partir desquelles l'appel de l'API Windows n'est pas pris en charge.

  • si vous avez un exécutable préexistant que vous ne pouvez pas modifier.

Si vous ne souhaitez pas activer la prise en charge globale dans ce cas (option (a)), l'option (c) (de PowerShell) peut fonctionner pour vous.


Concernant (c):

PowerShell active automatiquement la prise en charge VT (terminal virtuel) pour lui-même au démarrage (dans les versions récentes de Windows 10, cela s'applique Windows PowerShell et PowerShell Core).

Par conséquent, si vous relais la sortie d'un programme externe via PowerShell, les séquences VT sont reconnues ; utiliser Out-Host est le moyen le plus simple de le faire (Write-Host fonctionnerait aussi):

.\t.exe | Out-Host

Remarque: Utilisez Out-Host Uniquement si vous souhaitez imprimer sur la console; si, au contraire, vous voulez capturer la sortie du programme externe, utilisez simplement $capturedOutput = .\test.exe

Avertissement de codage de caractères : Windows PowerShell attend par défaut que la sortie des programmes externes utilise la page de codes OEM, telle que définie par les paramètres régionaux du système hérité (par exemple, 437 Sur les systèmes US-English) et comme indiqué dans [console]::OutputEncoding. Les programmes de la console .NET respectent ce paramètre automatiquement, mais pour les programmes non .NET (par exemple, les scripts Python) qui utilisent un codage différent (et produisent non seulement une sortie pure ASCII (dans le 7 bits)), vous devez (au moins temporairement) spécifier cet encodage en l'assignant à [console]::OutputEncoding; par exemple, pour UTF-8:
[console]::OutputEncoding = [Text.Encoding]::Utf8.
Notez que ceci est non seulement nécessaire pour la solution de contournement des séquences VT, mais généralement nécessaire pour que PowerShell restitue correctement les caractères non ASCII .

PowerShell Core, malheureusement, à partir de la version 6.1.0-preview.4, la page de codes OEM est également par défaut, mais cela devrait être considéré comme un bug , étant donné que PowerShell Core par défaut est UTF-8 sans BOM.

29
mklement0

Merci à l'utilisateur mklement0 de m'avoir informé que le support VT n'est pas activé automatiquement. Cela m'a fait regarder dans la bonne direction et j'ai trouvé ce message utile .

Donc, pour répondre à ma question: ajouter ou définir la clé de registre

HKCU:\Console  -  [DWORD] VirtualTerminalLevel = 1

Redémarrez la console et cela fonctionne.

8
Swonkie