Mostrar Unicode en PowerShell
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:
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.
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 .
- 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
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
$OutputEncoding
en 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 esSimSun-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 laFonts
pestañ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 a
65001
, la página de códigos UTF-8 (que generalmente se hace conchcp 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
$OutputEncoding
variable de preferencia (al decodificar la salida de programas externos, se[Console]::OutputEncoding
aplica 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 $PROFILE
archivo.
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]::OutputEncoding
ya no es estrictamente necesario, pero aún tendrá que configurarlo $OutputEncoding
(lo cual no es necesario en PowerShell Core , donde $OutputEncoding
ya 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.exe
yfindstr.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.
- Hasta Windows 8.1, esto incluía incluso utilidades estándar de Windows como
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-Encoding
pará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-Encoding
como con-Encoding utf8
, tendrías que usar'utf8BOM'
.
- 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
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
65001
primero 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
$OutputEncoding
variable 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
€: 1
incluso con la configuración predeterminada:
node -pe "process.argv[1] + ': ' + process.argv[1].length" €
- 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
[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$OutputEncoding
solo cubre el aspecto de entrada (al programa externo).
[Console]::InputEncoding
establece 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) :
chcp
Un valor activo para65001
romper 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 laWriteFile()
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ódigos65001
vigente, 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 65001
desde 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 chcp
los 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.
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:
Por ejemplo, con la fuente de consola Courier New , se muestran símbolos de reemplazo en lugar de caracteres CJK en una consola PowerShell:
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:
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 : *新宋体
Si instala el "Terminal Windows" de Microsoft desde Microsoft Store (o la versión Preview), viene preconfigurado para localización Unicode completa.
Aún no puedes ingresar comandos con caracteres especiales... ¡a menos que uses WSL! 😍
Me enfrentaba a un desafío similar al trabajar con Amazon Translate . Instalé el terminal desde la Tienda Windows y ¡ahora me funciona!
PowerShell ISE es una opción para mostrar caracteres extranjeros: korean.txt
es 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]