Как стать автором
Обновить

Комментарии 37

Я извиняюсь, а разве chcp unicode либо chcp 1251 не помогут?
Не поможет.

chcp 1251
test-1.ps1
$ErrorActionPreference = "Stop"
chcp 1251
& $PSScriptRoot\ConsoleApp1.exe


Результат выполнения


chcp 65001
test-2.ps1
$ErrorActionPreference = "Stop"
chcp 65001
& $PSScriptRoot\ConsoleApp1.exe


Результат выполнения

Русские символы? Кажется, вы хотели сказать "кириллица".

Не обижайтесь, но… Идет 2017 год, все человечество уже лет 15-17 точно перешло на Unicode. И только в Windows нужны какие-то эзотерические заклинания, вспоминать, что такое магические 866 и 1251. Понимаю, что все это видимо ради совместимости с приложениями 30-летней давности, но все же, можно было бы придумать и более изящное решение, особенно учитывая, что PowerShell — относительно недавнее изобретение и ему по большому счету совместимость с 30-летними приложениями не нужна.

Как хорошо, что есть люди, которые верят в существование серебряной пули.
Если немного глубже погрузиться в изучение стандарта unicode то можно узнать, что он состоит из двух основных разделов: универсальный набор символов (universal character set) и семейство кодировок (unicode transformation format). Так как в статье озвучена проблема кодировок, то посмотрим, какой зоопарк нам предоставляет unicode, а это UTF-8, UTF-16, UTF-32 + модификации LE / BE, ну и экзотика типа UTF-7, UTF-9, UTF-18. Так что проблемы кодировок символов с приходом unicode никуда не делись.

Unicode конечно несовершенен, как и все в этом мире. Но UTF-8 покрывает значительно большее количество случаев и намного более удобен, чем подобные костыли с code pages.


Я не знаток всех мировых языков. На повседневном уровне использую три: русский, английский, испанский. У меня в альтернативной операционной системе, что в консоли, что в любом другом приложении можно свободно использовать и комбинировать эти языки как угодно. При необходимости можно использовать еще сколько угодно языков. Да, наверное, какие-то проблемы с редкими символами из японского/китайского или малаяламского могут возникнуть, специально этим не интересовался.


В общем, Unicode — может быть и не всеобъемлющее решение, но однозначно намного более универсальное, чем полуработающие костыли (автор, насколько я понимаю, так и не добился работы без предупреждений во всех ситуациях). Допустим, если у нас существует необходимость работать с 2-3 языками одновременно, то я не вижу возможного решения вообще.


И это в 2017 году, когда по улицам скоро начнут ездить робомобили с искусственным интеллектом, память компьютеров измеряется десятками, если не сотнями гигабайт, а скорость процессоров дошла до физического предела… Но до сих пор в консоли Windows существуют ограничения 30-летней давности, когда компьютеры были слабее, чем самый слабый процессор в наручных часах...

Но UTF-8 покрывает значительно большее количество случаев и намного более удобен, чем подобные костыли с code pages.

А почему именно UTF-8?

Был опыт в попытке подружить вывод консоли TalendStudio с со сборочным агентом bamboo работающем под linux, вот только первый отправлял в stdout данные в кодировке UTF-16 а агент считывал их используя кодировку UTF-8. Так что использование unicode и не windows стека технологий в общем случае не спасет от возникновения проблем.

Ну и не надо забывать, что первоначально была задача решить проблему производства. :)
PowerShell — относительно недавнее изобретение и ему по большому счету совместимость с 30-летними приложениями не нужна.

Да, конечно, вы правы. И поэтому так такой совместимости по умолчанию и не предусмотрено: приложения, которые пользуются современными юникодовыми API (WriteConsoleW), будут печатать вывод нормально, а для устаревших приложений нужны бубны (некоторые сорта которых описаны в посте). К сожалению, приложений, которые не пользуются современными юникодовыми API, ещё очень много. Многие рантаймы языков программирования также этот режим вывода не поддерживают, что ещё печальнее.


А в линуксе как вы будете запускать программу, которая выводит UTF-16 в stdout, и чтоб этот текст отобразился на терминале?


(Я не утверждаю, что вы не сможете это сделать, просто мне действительно интересно посмотреть на решение.)

Во-первых, приложение, которое выводит на stdout интерактивный контент не в том, что указано в переменных локализации LC_*, надо исправлять, а не жить с этим. Это — ошибка, а не нормальное поведение.


Во-вторых, если очень нужно — большинство эмуляторов терминала умеют установить произвольную кодировку в качестве отображаемой, в том числе варианты UTF16.

приложение, которое выводит на stdout интерактивный контент не в том, что указано в переменных локализации LC_*, надо исправлять, а не жить с этим. Это — ошибка, а не нормальное поведение.

В этом я с вами тоже полностью согласен! Приложения, которые пытаются использовать функции семейства WriteConsoleA (которые по определению работают в текущей OEM-кодировке), чтобы выводить текст в другой кодировке, тоже надо исправлять. В Windows, если вам угодно, переменные локализации LC_* всегда константы и указывают UTF-16 кодировку, для которой есть соответствующее семейство функций вывода на экран. К сожалению, многие программы это игнорируют и пытаются совать в OEM-функции тексты в своих кодировках, что иногда и вызывает проблемы.


если очень нужно — большинство эмуляторов терминала умеют установить произвольную кодировку в качестве отображаемой, в том числе варианты UTF16.

А это не испортит вывод предыдущих команд в том же терминале? Пожалуй, для каких-то единичных программ всё-таки лучше пайпать их вывод в iconv.

Приложения, которые пытаются использовать функции семейства WriteConsoleA [...] тоже надо исправлять

Только вот Microsoft с вами, боюсь, не согласен. Иначе бы делали какие-то телодвижения по объявлению *A функций deprecated и пытались бы как-то форсировать переход человечества в светлое будущее. Вот здесь говорят, что их пытаются deprecate'ить, но только по каким-то одиночным библиотекам типа winsock2.


А это не испортит вывод предыдущих команд в том же терминале?

Не должно. Хотя бы потому, что терминал, вообще говоря, не имеет возможности переинтерпретировать какую-то часть старого потока символов при таком переключении кодировки (хотя бы потому, что эту часть еще как-то выделить и запомнить надо, а это потребует весьма нетривиальных телодвижений). Это же не браузер, в котором кодировку всего документа переключают — документа-то нет.

Депрекейтить необязательно, достаточно только лишь подробно рассмотреть вопрос. У функции WriteConsoleA есть вполне определённое поведение: вывести строку в текущей OEM-кодировке (ну, вообще говоря, просто в текущей кодировке консоли в соответствии с SetConsoleOutputCP, которая по умолчанию инициализируется из OEM).


Если конкретному приложению нужно именно это (мне сложно представить себе современное приложение с такими нуждами, но мало ли) — оно вполне легитимно вправе использовать это семейство функций.


Если же конкретное приложение хочет выводить какой-то национальный текст вне зависимости от кодировки терминала — оно должно использовать соответствующие юникодовые функции (a la WriteConsoleW). Вот и всё.

Не обижайтесь, но во-первых, отучайтесь говорить за всё человечество, во-вторых, unicode в той же ntfs появился в 1993 году, когда… в каком состоянии был софт, который вы используете, что вам позволяет не зная в принципе матчасти игнорируя реальный кейс по powershell пускаться в публичные пространные рассуждения внезапно об операционной системе в целом, человечестве и необходимости обратной совместимости?

Про обратную совместимость: благодаря этим бесконечным костылям в windows 10.0 запускается и работает то, что писалось во времена windows 3.5. А уж без специфических программ если — то windows 5 софт работает без проблем в windows 10.

Вы на каком красноглазии сидите, что позволяете себе свысока подобные сентенции публично? Там можно десятилетний бинарник запустить без проблем, да?
НЛО прилетело и опубликовало эту надпись здесь
Что не имеет никакого отношения к тому, что тот человек, которому я отвечал — зачем-то проигнорировал тему хорошего поста про powershell и кодировки, да начал спрашивать с автора поста как с Марка Руссиновича с каким-то неуместным выпендрёжем про Windows без знания матчасти. :)

Простите, что так задел вас.


Не знаю, как с бинарной совместимостью с Linux. Она там есть, но насколько хорошая — не знаю, т.к. весь необходимый мне софт — opensource — поэтому никогда не нужна была бинарная совместимость. Раньше у меня было время читать lkml и множество других источников информации о развитии Linux, и помню, что этот вопрос обсуждался и совместимость старались сохранить.


Предполагаю, что десятилетний бинарник скорее всего можно будет запустить.


Что касается поддержки Unicode в ntfs — не знаю, что тут сказать. Может быть это требовалось по каким-то причинам для ntfs, про файловые системы Linux/Unix можно сказать, что они поддерживали Unicode с самого начала существования, еще до возникновения Unicode, так как для большинства файловых систем Linux/Unix — имя файла — это просто набор байтов, который они никак не пытаются интерпретировать. То же самое относится, естественно, к содержимому файла. Поэтому можно использовать хоть Unicode, хоть что угодно вместо него.


Но тут речь не о сравнении операционных систем — я не пытался и не хотел начинать такой разговор. Просто описанное в статье мне показалось костылями, да еще и неработающими. Выразил свое удивление, вот и все. Может быть все эти неудобства стоят того, чтобы кто-то мог запустить на Windows 10 программу для Windows 3.11. Меня это удивляет, конечно, потому что таких людей наверняка меньше 1%, и почему бы им не использовать копию Win 3.11 или виртуальную машину, вместо того, чтобы миллионы людей по всему миру испытывали неудобства.

Мне кажется, эта полемика возникла из взаимонепонимания двух ортогональных точек зрения: Ваша, "как надо писать программы"(точка зрения разработчика) и автора, "как заставить работать то, что написали другие"(т.зр. сисадмина). Вы поавы, ситуацию надо менять в корне. Но пока она не исправлена, проблема есть и её надо решать в рамках задач по эксплуатации независимо от того, что "есть правильный путь". Так что да, автор тоже прав, что ищет пути.

Я не обладаю всей информацией, чтобы предложить решение. Всю жизнь использую Linux — так сложилось, что Linux увидел раньше Windows, еще где-то в 95 или 96 году. С Windows знаком постольку-поскольку, сталкиваюсь лишь на компьютерах знакомых.


Поэтому мне сложно предложить техническое решение, решающее данную проблему. Просто удивило — все это выглядит как нагромождение костылей. Представляю какое астрономическое количество человеко-лет тратит Microsoft на поддержку этой совместимости, в том числе откровенно дебильных codepages, которые, мне казалось, давно остались лишь в музеях. А затем пользователи Windows по всему миру тратят свои человеко-часы, чтобы построить новые костыли поверх старых, чтобы обойти эти грабли древних кодировок.


В итоге, полмира тратит время впустую, лишь бы кто-то мог запустить supercalc.exe 1986 года на операционной системе 2015-го года. Мне почему-то это не кажется поводом для гордости. Есть какой-то баланс между ломанием совместимости в каждой новой версии и фанатичной поддержкой совместимости. Кому нужно работать с приложениями 20-30 летней давности, скорее всего будет делать это на старом железе со старой системой. В крайнем случае, почему бы не установить виртуальную машину.


Зачем подвергать людей таким пыткам, что они даже банальный скрипт невозможно написать без танцев с бубном? Неужели не существует разумного способа решить данную проблему раз и навсегда? Например, сказать: «пусть cmd и все прочее, что потенциально может использоваться для старых приложений, будет использовать codepages, а для PowerScript мы делаем стандартом Unicode?»

Когда ваша ОС стоит в куче мегакорпораций, и мегакорпорации заносят к тебе кучу бабла, и какой-нибудь supercalc.exe перестает работать, то с этим что-то надо делать.

Ну, Linux тоже стоит в куче мегакорпораций, и ничего, как-то умудряется поддерживать всюду сквозной unicode без костылей. В любом приложении, консольном или GUI, написанном на любом языке программирования, с использованием любого фреймворка, могу вводить текст на нескольких языках, и он будет отображаться всюду без проблем, сохраняться, загружаться. По-моему, это просто необходимое условие для минимально комфортного уровня работы, потому что за пределами Северной Америки, почти всем людям приходится ежедневно использовать два и более языка.


Про supercalc — не верю, что кто-то покупает новую машину с i7, устанавливает Windows 10, и все это, для того, чтобы запустить supercalc. Если такие пользователи и есть, то у них стоит какое-нибудь древнее железо, на котором крутится DOS, Windows 3.11 или что-то подобное.


Понятно, что полная статистика есть только у Microsoft, да и есть ли?.. Но все же сомнительно, чтобы такие пользователи составляли хоть сколько-нибудь значительный процент среди покупателей тех же Windows 7, Windows 10.

А мне вот интересно, если бы в статье был описан более частный случай с несогласованностью кодировок UTF-16 в приложении, UTF-8 в «консоли» Вы бы тоже писали, что эта проблема вот уже 100 лет как решена в linux, а Microsoft только на бабки пользователей разводит? :)

Ну и как я писал выше — путаете набор символов (char set) и кодировку (encoding).

Я нигде не писал, что «Microsoft разводит пользователей на бабки». И отлично знаю разницу между char set и encoding, хотя частенько использую термин unicode как синоним utf-8, прошу за это прощения.


На самом деле удивило, что до сих пор людям приходится бороться с code pages причем в современных языках и приложениях. Когда уже много лет не испытывал абсолютно никаких проблем в этой области, подобные проблемы на самом деле удивляют. 866? 1251? Какие-то хаки, чтобы прочитать кириллицу в выводе скрипта? Это действительно удивительно при взгляде с другой стороны баррикад.


Причем я ни в одном комментарии не критиковал Microsoft, только лишь выражал искреннее недоумение.

Простите, что так задел вас

Какой унылый демагог. Ваше мнение, безусловно, очень важно, держите в курсе.
благодаря этим бесконечным костылям в windows 10.0 запускается и работает кое-что, что писалось во времена windows 3.5

жизнефикс
Это просто баг на самом деле.
PowerShell — относительно недавнее изобретение и ему по большому счету совместимость с 30-летними приложениями не нужна.

Это вам не нужно и мне не нужно, а у майкрософта это основная бизнес-фича и священная корова.
Идет 2017 год, все человечество уже лет 15-17 точно перешло на Unicode. И только в Windows нужны какие-то эзотерические заклинания

Тут не очень понятно, к чему вы это. Я вот при установке Windows на ноутбук, погорячившись, назвал профиль «Андрей». Ну и в результате, то там то сям вылазит:

Qt проект, положенный в такую папку, вообще отказывается собираться, и так далее.
Нет пока что в мире совершенства, хоть и 2017 год на дворе.
Особенно доставляет то, что у меня все языковые настройки немецкие — с этой стороны тоже вылазят свои трогательные косяки.
С другой стороны, есть пользователи (коих, вероятно, большинство), которые с такой проблемой не сталкивались, просто потому, что не используют «проблемное» сочетание продуктов за ненадобностью.
Автор в одном конкретном случае получил вывод в неверной кодировке, разобрался что к чему, исправил это дело и поделился.
Мне вот по долгу службы приходится разрабатывать десктопное приложение, локализованное для многих языков, при этом используя IDE с весьма кривой поддержкой юникода, так у меня целая коллекция таких вот случаев (хотя они слишком частные, и не будут интересны широкому кругу).
Шаг за шагом эти проблемы решаются, но пройдёт ещё довольно много времени, прежде чем все эти болячки окончательно исчезнут.
А при чем тут кстати вообще powershell? Вот пример приложения:
using System;
using System.Text;

class Program
{
	static void Main(string[] args)
	{
		Console.OutputEncoding = Encoding.UTF8;
		Console.WriteLine("c'est-à-dire хелло Βικιπαίδεια");
	}
}

вот скрипт (1.ps1 в UTF8-BOM):
Write-Output "c'est-à-dire хелло Βικιπαίδεια"
&"C:\Users\Alex\Documents\visual studio 2017\Projects\SamplePowershellApp\SamplePowershellApp\bin\Debug\SamplePowershellApp.exe"

Результат:image
Самая большая проблема данного решения — требует изменения кода устанавливаемого приложения. Это далеко не всегда возможно.
А при чем тут powershell? в исходниках экзешника уже захардкожена кодировка вывода, тут уж с какими бубнами ни пляши, ничего иного и не получится.
Так большая же часть программ написана вот таким образом:
	static void Main(string[] args)
	{
		Console.WriteLine("c'est-à-dire хелло Βικιπαίδεια");
	}
Ну так запустите экзешник из студии, и получите ровно тот же результат. Так и не стало понятно, при чем тут powershell

Действительно, при чём здесь PowerShell, если автор решает проблему в приложении к powershell скриптам? Как, как он посмел подумать про powershell, когда решал, как отобразить некракозябры через powershell?!!

НЛО прилетело и опубликовало эту надпись здесь
Данные скрипты один из кирпичиков для Continuous Deployment, соответственно стояла задача сделать все логи в нормальной кодировке, чтобы при разборе проблем уметь сразу всю необходимую информацию.
Эх, еще-бы такую-же проблему для CMD/PsExec решить…
Занятно, спасибо.

Для себя эту проблему (в терминале, а не в ISE) решил установкой кастомного терминала и макросами на смену шрифта вывода — на удалённом хосте включаем шрифт Terminal, и кракозябры превращаются в читаемый вывод.
Сегодня столкнулся с кракозябрами при выводе wbadmin в PowerShell — вопрос был решён запуском той же команды в psexec — всё отработало отлично, вывод читабелен.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации