Mostrar Unicode en PowerShell

Resuelto Dhiwakar Ravikumar asked hace 6 años • 7 respuestas

Lo que intento lograr debería ser bastante sencillo, aunque PowerShell intenta hacerlo más difícil.

Quiero mostrar la ruta completa de los archivos, algunos con caracteres árabes, chinos, japoneses y rusos en sus nombres.

Siempre obtengo algún resultado indescifrable, como el que se muestra a continuación:

Ingrese la descripción de la imagen aquí

La salida que se ve en la consola está siendo consumida tal cual por otro script. ¿La salida contiene ? en lugar de los personajes reales.

El comando ejecutado es

(Get-ChildItem -Recurse -Path "D:\test" -Include *unicode* | Get-ChildItem -Recurse).FullName

¿Existe una manera fácil de iniciar PowerShell (a través de la línea de comando o de una manera que pueda escribirse en un script) de modo que el resultado se vea correctamente?

PD: He respondido a muchas preguntas similares sobre Stack Overflow, pero ninguna de ellas tiene mucha información aparte de llamarlo un problema del subsistema de la consola de Windows.

Dhiwakar Ravikumar avatar Mar 25 '18 20:03 Dhiwakar Ravikumar
Aceptado

Nota:

  • En Windows, con respecto a la representación de caracteres Unicode , lo que importa principalmente es la elección de la fuente / aplicación de consola (terminal) .

    • Hoy en día, usar Windows Terminal , que se distribuye y actualiza a través de Microsoft Store desde Windows 10, es un buen reemplazo para el host de consola heredado (ventanas de consola proporcionadas por conhost.exe), ya que brinda compatibilidad superior con caracteres Unicode. En Windows 11 22H2, Windows Terminal incluso se convirtió en la consola (terminal) predeterminada .
  • Con respecto al procesamiento programático de caracteres Unicode cuando se comunica con programas externos , y también importa $OutputEncoding, consulte a continuación.[Console]::InputEncoding[Console]::OutputEncoding


La perspectiva de PowerShell (Core) 7+ (consulte la siguiente sección para Windows PowerShell ), independientemente de los problemas de representación de caracteres (también tratados en la siguiente sección), con respecto a la comunicación con programas externos :

  • En plataformas tipo Unix , PowerShell Core usa UTF-8 de forma predeterminada .

  • En Windows , es la configuración regional del sistema heredado , a través de su página de códigos OEM , la que determina la codificación predeterminada en todas las consolas, incluidas las ventanas de la consola Windows PowerShell y PowerShell Core, aunque las versiones recientes de Windows 10 ahora permiten configurar la configuración regional del sistema en la página de códigos. 65001(UTF-8) ; tenga en cuenta que la función todavía está en versión beta al momento de escribir este artículo y su uso tiene consecuencias de gran alcance ; consulte esta respuesta .

    • Si usa esa característica, las ventanas de la consola PowerShell Core serán automáticamente compatibles con UTF-8, aunque en Windows PowerShell también tendrá que configurarlo $OutputEncodingen UTF-8 (que en Core ya tiene por defecto UTF-8), como mostrado a continuación.

    • De lo contrario, especialmente en versiones anteriores de Windows, puede utilizar el mismo método que se detalla a continuación para Windows PowerShell.


Hacer que la ventana de la consola de Windows PowerShell reconozca Unicode (UTF-8) :

  • Elija una fuente TrueType (TT) que admita las secuencias de comandos específicas (sistemas de escritura, alfabetos) cuyos caracteres desea mostrar correctamente en la consola:

    • Importante : si bien todas las fuentes TrueType admiten Unicode en principio , normalmente solo admiten un subconjunto de todos los caracteres Unicode, es decir, los correspondientes a escrituras (sistemas de escritura) específicos
      , como la escritura latina, la escritura cirílica (rusa),... En su caso particular, si debe admitir caracteres árabes, chinos, japoneses y rusos, su única opción es SimSun-ExtB, que está disponible solo en Windows 10 .
      Consulte Wikipedia para obtener una lista de qué fuentes de Windows se dirigen a qué scripts (alfabetos).

    • Para cambiar la fuente, haga clic en el icono en la esquina superior izquierda de la ventana y seleccione Properties, luego cambie a la Fontspestaña y seleccione la fuente TrueType de su interés.

      • Consulte esta respuesta SU de not2quibit para saber cómo hacer que fuentes adicionales estén disponibles.
  • Además, para una correcta comunicación con programas externos :

    • La página de códigos de la ventana de la consola debe cambiarse a65001 , la página de códigos UTF-8 (que generalmente se hace con chcp 65001, que, sin embargo, no se puede usar directamente desde una sesión de PowerShell [1] , pero el siguiente comando de PowerShell tiene el mismo efecto) .

    • Se debe indicar a Windows PowerShell que use UTF-8 para comunicarse con utilidades externas también , tanto al enviar entradas de canalización a programas externos, como a través de su $OutputEncodingvariable de preferencia (al decodificar la salida de programas externos, se [Console]::OutputEncodingaplica la codificación almacenada).

El siguiente encantamiento mágico en Windows PowerShell hace esto (como se indicó, esto se realiza implícitamentechcp 65001 ):

$OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding =
                    New-Object System.Text.UTF8Encoding

Para conservar estas configuraciones , es decir, para que sus futuras sesiones interactivas de PowerShell sean compatibles con UTF-8 de forma predeterminada, agregue el comando anterior a su $PROFILEarchivo.

Nota: Las versiones recientes de Windows 10 ahora permiten configurar la configuración regional del sistema en la página de códigos 65001(UTF-8) (la función aún está en versión beta a partir de Windows 10 versión 1903), lo que hace que todas las ventanas de la consola tengan como valor predeterminado UTF-8, incluido Windows PowerShell. .
Si usa esa función, configurar [Console]::InputEncoding/ [Console]::OutputEncodingya no es estrictamente necesario, pero aún tendrá que configurarlo $OutputEncoding(lo cual no es necesario en PowerShell Core , donde $OutputEncodingya está predeterminado UTF-8).

Importante :

  • Esta configuración supone que cualquier utilidad externa con la que se comunique espera una entrada codificada en UTF-8 y produce una salida UTF-8 .

    • Las CLI escritas en Node.js cumplen ese criterio, por ejemplo.
    • Los scripts de Python, si se escriben teniendo en cuenta la compatibilidad con UTF-8, también pueden manejar UTF-8 (consulte esta respuesta ).
  • Por el contrario, estas configuraciones pueden interrumpir las utilidades (más antiguas) que solo esperan una codificación de un solo byte, como lo implica la página de códigos OEM heredada del sistema.

    • Hasta Windows 8.1, esto incluía incluso utilidades estándar de Windows como find.exey findstr.exe, que se han solucionado en Windows 10.
    • Consulte la parte inferior de esta publicación para saber cómo evitar este problema cambiando a UTF-8 temporalmente, a pedido para invocar una utilidad determinada.
  • Estas configuraciones se aplican solo a programas externos y no están relacionadas con las codificaciones que los cmdlets de PowerShell usan en la salida :

    • Consulte esta respuesta para conocer las codificaciones de caracteres predeterminadas utilizadas por los cmdlets de PowerShell; en resumen: si desea que los cmdlets en Windows PowerShell tengan de forma predeterminada UTF-8 (lo que PowerShell [Core] v6+ hace de todos modos), agréguelo $PSDefaultParameterValues['*:Encoding'] = 'utf8'a su archivo $PROFILE, pero tenga en cuenta que esto afectará todas las llamadas a cmdlets con un -Encodingparámetro en sus sesiones, a menos que El parámetro se utiliza explícitamente; También tenga en cuenta que en Windows PowerShell siempre obtendrá archivos UTF-8 con BOM ; por el contrario, en PowerShell [Core] v6+ , que de forma predeterminada es UTF-8 sin BOM (tanto en ausencia -Encodingcomo con -Encoding utf8, tendrías que usar 'utf8BOM'.

Información de antecedentes opcional

Quitándome el sombrero a eryksun por todos sus aportes.

  • Mientras una fuente TrueType está activa , el búfer de la ventana de la consola conserva correctamente los caracteres Unicode (no ASCII). incluso si no se muestran correctamente ; es decir, aunque puedan aparecer genéricamente como?, para indicar la falta de compatibilidad con la fuente actual, puedes copiar y pegar dichos caracteres en otro lugar sin pérdida de información, como señala eryksun.

  • PowerShell es capaz de enviar caracteres Unicode a la consola incluso sin haber cambiado 65001primero a la página de códigos .
    Sin embargo, eso por sí solo no garantiza que otros programas puedan manejar dicha salida correctamente - ver más abajo.

  • Cuando se trata de comunicarse con programas externos a través de stdout ( piping ) , PowersShell usa la codificación de caracteres especificada en la $OutputEncodingvariable de preferencia , que por defecto es ASCII(!) en Windows PowerShell , lo que significa que cualquier carácter que no sea ASCII se translitera a caracteres literales ? . resultando en pérdida de información . (Por el contrario, es digno de elogio que PowerShell Core (v6+) ahora use UTF-8 (sin BOM) como codificación predeterminada, de manera consistente).

    • Sin embargo, por el contrario, pasar argumentos que no son ASCII (en lugar de salida estándar (canalizada)) a programas externos no parece requerir ninguna configuración especial (no me queda claro por qué funciona); por ejemplo, el siguiente comando de Node.js regresa correctamente €: 1incluso con la configuración predeterminada:
      node -pe "process.argv[1] + ': ' + process.argv[1].length" €
  • [Console]::OutputEncoding:

    • controla qué codificación de caracteres se asume cuando la consola traduce la salida del programa en caracteres de visualización de la consola.
    • También le indica a PowerShell qué codificación asumir al capturar resultados de un programa externo .
      El resultado es que si necesita capturar la salida[Console]::OutputEncoding de un programa que produce UTF-8, también debe configurarlo en UTF-8; La configuración $OutputEncodingsolo cubre el aspecto de entrada (al programa externo).
  • [Console]::InputEncodingestablece la codificación para la entrada del teclado en una consola [2] y también determina cómo la CLI de PowerShell interpreta los datos que recibe a través de stdin (entrada estándar).

  • Si cambiar la consola a UTF-8 durante toda la sesión no es una opción, puede hacerlo temporalmente, para una llamada determinada :

      # Save the current settings and temporarily switch to UTF-8.
      $oldOutputEncoding = $OutputEncoding; $oldConsoleEncoding = [Console]::OutputEncoding
      $OutputEncoding = [Console]::OutputEncoding = New-Object System.Text.Utf8Encoding
    
      # Call the UTF-8 program, using Node.js as an example.
      # This should echo '€' (`U+20AC`) as-is and report the length as *1*.
      $captured = '€' | node -pe "require('fs').readFileSync(0).toString().trim()"
      $captured; $captured.Length
    
      # Restore the previous settings.
      $OutputEncoding = $oldOutputEncoding; [Console]::OutputEncoding = $oldConsoleEncoding
    
  • Problemas en versiones anteriores de Windows (anteriores a W10) :

    • chcpUn valor activo para 65001romper la salida de la consola de algunos programas externos e incluso archivos por lotes en general en versiones anteriores de Windows puede haber surgido en última instancia de un error en la WriteFile()función API de Windows (como también la usa la biblioteca C estándar), que informaba erróneamente el número de caracteres en lugar de bytes con la página de códigos 65001vigente, como se analiza en esta publicación de blog .
  • Los síntomas resultantes, según un comentario de bobince sobre esta respuesta de 2008, son: "Tengo entendido que las llamadas que devuelven una cantidad de bytes (como fread/fwrite/etc) en realidad devuelven una cantidad de caracteres. Esto causa una amplia variedad de síntomas, como lectura de entrada incompleta, bloqueos, archivos por lotes rotos, etc.


Alternativas superiores a la consola nativa de Windows (terminal),conhost.exe

eryksun sugiere dos alternativas a las ventanas nativas de la consola de Windows ( conhost.exe), que proporcionan una representación de caracteres Unicode mejor y más rápida , debido al uso de la moderna API DirectWrite/DirectX acelerada por GPU en lugar de la "antigua implementación GDI [que] no puede manejar scripts complejos, caracteres que no son BMP o fuentes de reserva automática".

  • Terminal Windows de código abierto propio de Microsoft , que se distribuye y actualiza a través de Microsoft Store desde Windows 10; consulte aquí para obtener una introducción.

  • Alternativa de terceros de larga data, ConEmu , que tiene la ventaja de funcionar también en versiones anteriores de Windows.


[1] Tenga en cuenta que ejecutar chcp 65001desde dentro de una sesión de PowerShell no es efectivo, porque .NET almacena en caché la codificación de salida de la consola al inicio y no tiene conocimiento de los cambios posteriores realizados con (solo se recogen chcplos cambios realizados directamente a través de ).[console]::OutputEncoding]

[2] No tengo claro cómo se manifiesta eso en la práctica; Cuéntanos, si lo sabes.

mklement0 avatar Mar 25 '2018 22:03 mklement0

Respuesta elaborada por Alexander Martin . Para fines de prueba, he creado algunas carpetas y archivos con nombres válidos de diferentes subrangos Unicode de la siguiente manera:

Nombres válidos

Por ejemplo, con la fuente de consola Courier New , se muestran símbolos de reemplazo en lugar de caracteres CJK en una consola PowerShell:

Mensajero nuevo

Por otro lado, con la fuente de la consola SimSun , se muestran símbolos de reemplazo (poco visibles) en lugar de caracteres árabes y hebreos, mientras que los caracteres CJK parecen mostrarse correctamente:

SimSun

Tenga en cuenta que todos los símbolos de reemplazo simplemente se muestran, mientras que los caracteres reales se conservan, como puede ver en el siguiente Copiar y pegar desde la consola PowerShell anterior:

(Get-ChildItem 'D:\bat\UnASCII Names\' -Dir).Name

Producción:

Arabic (عَرَبِيّ‎)
CJK (中文(繁體))
Czech (Čeština)
Greek (Γρεεκ)
Hebrew (עִבְרִית)
Japanese (日本語)
MathBoldScript (𝓜𝓪𝓽𝓱𝓑𝓸𝓵𝓭𝓢𝓬𝓻𝓲𝓹𝓽)
Russian (русский язык)
Türkçe (Türkiye)
‹angles›
☺☻♥♦

En aras de la exhaustividad, aquí se muestran los valores de registro apropiados para habilitar más fuentes para el símbolo del sistema de Windows (esto también funciona para la consola de Windows PowerShell):

(Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont' |
    Select-Object -Property [0-9]* | Out-String).Split(
        [System.Environment]::NewLine,
        [System.StringSplitOptions]::RemoveEmptyEntries) |
     Sort-Object

Salida de muestra:

0       : Consolas
00      : Source Code Pro
000     : DejaVu Sans Mono
0000    : Courier New
00000   : Simplified Arabic Fixed
000000  : Unifont
0000000 : Lucida Console
932     : *MS ゴシック
936     : *新宋体
JosefZ avatar Mar 28 '2018 12:03 JosefZ

Si instala el "Terminal Windows" de Microsoft desde Microsoft Store (o la versión Preview), viene preconfigurado para localización Unicode completa.

Vista previa de terminal de Windows con muñeco de nieve ⛄, árabe (عَرَبِيّ‎), CJK (中文(繁體)), checo (Čeština), griego (Γρεεκ), hebreo (עִבְרִית), japonés (日本語), MathBoldScript (𝓜𝓪𝓽𝓱𝓑 𝓸𝓵𝓭𝓢𝓬𝓻𝓲𝓹𝓽), ruso (русский язык), Türkçe (Türkiye), ‹ángulos›, ☺☻♥♦

Aún no puedes ingresar comandos con caracteres especiales... ¡a menos que uses WSL! 😍

Usando WSL, podemos ejecutar echo "snowman ⛄"

Neal Ehardt avatar Mar 11 '2021 19:03 Neal Ehardt

Me enfrentaba a un desafío similar al trabajar con Amazon Translate . Instalé el terminal desde la Tienda Windows y ¡ahora me funciona!

user2630981 avatar Mar 10 '2021 02:03 user2630981

PowerShell ISE es una opción para mostrar caracteres extranjeros: korean.txtes un archivo codificado en UTF-8:

cd C:\Users\js
Get-Content korean.txt

Producción:

The Korean language (South Korean: 한국어/韓國語 Hangugeo; North
Korean: 조선말/朝鮮말 Chosŏnmal) is an East Asian language
spoken by about 77 million people.[3]
js2010 avatar Jul 23 '2019 03:07 js2010