
Я счёл это небезынтересным подарком ко дню рождения (по приятному совпадению, 25 ноября мне исполнилось 33 года). Однако в тот же день, задавшись вопросом «Как принять вывод
Во-первых, при вызове команды методом require('child_process').exec(…) Node ожидает от неё вывода в кодировке
Во-вторых, если дочерний консольный процесс изменит кодировку консоли, то будет воздействовать и на кодировку консоли родительского процесса Node (в частности, на вывод методом
А теперь немного подробностей.
С первым из двух найденных мною багов нетрудно столкнуться, если запустить самый простой скрипт вызова дочернего процесса с записью его вывода в буквальном виде в файл:
var fs = require('fs'); // file system
require('child_process').exec('dir', function(err, outstr){
fs.createWriteStream('testfile.txt', {
flags: 'w',
encoding: 'binary'
}).write(outstr);
});
Вместо русских букв в файле будет чепуха.
Как sdevalex справедливо предположил, для этой проблемы существует обходной путь: достаточно использовать
var forker = require('child_process');
var fs = require('fs'); // file system
forker.exec('chcp 65001 | dir', function(err, outstr){
fs.createWriteStream('testfile.txt', {
flags: 'w',
encoding: 'binary'
}).write(outstr);
});
Однако же на этом обходном пути вы можете наткнуться и на вторую ошибку, если захотите вывести результаты не только в файл, но и в консоль, для чего достаточно составить вот какой скрипт:
var clog = console.log;
clog('\nRunning under Node.js version ' + process.versions.node + ' on ' +
process.arch + '-type processor, ' + process.platform + ' platform.');
var forker = require('child_process');
var fs = require('fs'); // file system
forker.exec('chcp 65001 | dir', function(err, outstr){
fs.createWriteStream('testfile.txt', {
flags: 'w',
encoding: 'binary'
}).write(outstr);
clog('\n' + outstr);
});
Можете наткнуться. А можете, как ни странно, и не наткнуться. Зависит это от того, используются ли у вас в консоли растровые шрифты или векторные (в роли которых в Windows XP выступают шрифты Lucida Console), то есть от настройки в центре второй вкладки привычного диалогового окна свойств консоли:
![[окно свойств консоли]](https://habrastorage.org/getpro/habr/post_images/e61/b3e/636/e61b3e6367d26c3d0a3a4a684e6e4a2d.png)
Насколько я помню, в Windows XP по умолчанию в консоли используются растровые шрифты (поправьте меня, если я ошибаюсь). А значит, если вы не меняли у себя эту настройку, то вышеприведённый скрипт в файл («testfile.txt») будет выводить желаемый текст, а в консоль выведет нечто малопривлекательное:
![[скриншот консоли]](https://habrastorage.org/getpro/habr/post_images/8aa/d7c/8ba/8aad7c8ba95255487d254e7c6c933973.gif)
А всё это потому, что в растровой консоли команда «chcp» меняет только кодировку текста, выводимого командами; растровые шрифты не могут к ней подстроиться, так что даже вывод самóй команды «chcp» в консоли выглядит неприглядно:
![[скриншот chcp]](https://habrastorage.org/getpro/habr/post_images/973/3a8/c90/9733a8c9052610492e1e1dd3f6b497b1.gif)
Если же консоль у вас настроена на отображение текста векторными шрифтами (Lucida Console), то вы и не заметите этой проблемы, потому что у вас вывод скрипта будет выглядеть корректно в любой кодировке, какую бы вам ни вздумалось заранее задать в консоли
![[скриншот векторной консоли]](https://habrastorage.org/getpro/habr/post_images/8ff/8eb/d34/8ff8ebd34a8cce2d453fbd62ae380c16.gif)
На этом этапе волосы должны подняться дыбом на голове и мерно шевелиться. Потому что понятно, что перед нами необычайно коварная проблема, позволяющая разработчику (если он пользуется векторной консолью) буквально десятком строк кода сочинить такой скрипт, который у него у самогó будет прекрасно работать, а у массы некоторых других пользователей (в растровой консоли) станет работать преотвратительно.
Но что же это за проблема?
Быть может, Node не справляется с выводом в консоль Windows, потому что в JavaScript строки юникодовые, а в консоли Windows они в кодировке CP866? А вот и нет, дело не в этом — что нетрудно доказать простым тестовым выводом в консоль:
![[скриншот теста]](https://habrastorage.org/getpro/habr/post_images/d41/8b1/d42/d418b1d4247dc47220c87a68af227d0c.gif)
Быть может, Node переключается на мусор, когда выводимые символы выходят за пределы кодировки CP866? Тоже нет, и достаточно вывести строку
Оказывается, что справедлива другая догадка: этот мусор в растровой консоли имеет ту же природу, что и мусор, выводимый командою
Чтобы вполне продемонстрировать это, хватает несложного теста:
![[скриншот очередного теста]](https://habrastorage.org/getpro/habr/post_images/5e0/311/8b1/5e03118b15ba18b524072867b0637d3e.gif)
Как нетрудно видеть, «chcp 65001» из дочернего процесса воздействует на окно консоли родительского процесса (воздействует до тех пор, пока не будет подана команда «chcp 866» и не возвратит кодовую страницу CP866, используемую по умолчанию).
Понимание этой новой ошибки позволяет нам обнаружить более совершенный путь обхода ранее найденной ошибки. Вызвав «chcp 65001» перед
var clog = console.log;
clog('\nRunning under Node.js version ' + process.versions.node + ' on ' +
process.arch + '-type processor, ' + process.platform + ' platform.');
var forker = require('child_process');
var fs = require('fs'); // file system
forker.exec('chcp 65001 | dir', function(err, outstr){
fs.createWriteStream('testfile.txt', {
flags: 'w',
encoding: 'binary'
}).write(outstr);
forker.exec('chcp 866', function(){
clog('\n' + outstr);
});
});
Этот скрипт ужé способен невозбранно вывести безупречный текст не только в тестовый файл, но также и в консоль:
![[скриншот очередного теста]](https://habrastorage.org/getpro/habr/post_images/edd/3e6/c96/edd3e6c961148fdc9c0a4162df9d43d2.gif)
У этого обходного пути, при всей его безупречности, есть непреодолимый архитектурный недостаток: два вызова
Обе найденные ошибки были поведаны разработчикам Node через GitHub: donnerjack13589 вчера создал issue 2190, а я сегодня создал issue 2196.