preserve color when executing child_process.spawn
node.jsnode.js Problem Overview
I'm trying to execute a windows command through cmd.exe in node.js using child_process.spawn. It executes correctly, but only displays in default text color. How do I preserver the color. Is it possible?
var spawn = require('child_process').spawn,
cmd = spawn('cmd', ['/s', '/c', 'C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild c:\\test.sln']);
cmd.stdout.on('data', function(data){
process.stdout.write(data);
});
cmd.stderr.on('data', function(data){
process.stderr.write(data);
});
cmd.on('exit', function(code){
console.log(code);
});
When executing via node, the color is not preserved.
When executing via cmd.exe directly, the color is present. (This is the expected behavior). How do I get this behvior when executing via node.
node.js Solutions
Solution 1 - node.js
There are new 'stdio' option for child_process.spawn(). Try following:
spawn("path to executable", ["params"], {stdio: "inherit"});
"Inherit" means [0, 1, 2] or [process.stdin, process.stdout, process.stderr].
Solution 2 - node.js
crossplatform solution that worked for me was to use both shell: true
and stdio: 'inherit'
:
const spawn = require('child_process').spawn;
spawn('node', ['./child.js'], { shell: true, stdio: 'inherit' });
thanks @59naga https://github.com/nodejs/node/issues/2333
Solution 3 - node.js
If you are getting error:
> Cannot call method 'on' of null
Try this:
spawn("command", ["args"], { env : { FORCE_COLOR: true }});
works with mocha
Solution 4 - node.js
Try this instead:
var spawn = require('child_process').spawn
, command = 'C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild c:\\test.sln'
, cmd = spawn('cmd', ['/s', '/c', command], { customFds: [0,1,2] });
cmd.on('exit', function(code){
console.log(code);
});
Note that I'm not positive whether or not customFds
works on Windows. I know that it's old deprecated functionality doesn't work, but when only passing [0,1,2]
as the fd's, I think there is a special case for that.
I've been doing something similar here, but I've only ran that command on Unix machines. So let me know if that works on Windows.
Solution 5 - node.js
This doesn't fix the underlying issue (lack of a proper TTY stream) but it should help get around it.
If the sub-process you're running uses supports-color (https://www.npmjs.com/package/supports-color) like chalk, then you can set an environmental variable FORCE_COLOR
to any value and it will skip the rest of the checks. This will allow you to continue to use pipes (and capture/modify the returned data) unlike the inherit
fix.
There is also a node-pty (https://www.npmjs.com/package/node-pty) module that provides a .spawn
with the ability to pass a pty (pseudo tty) that may be a more holistic answer. I haven't played with it yet, and I'm not sure if it's cross platform or not.
Solution 6 - node.js
If you want to either keep the color or add some notation for the output, you can try the code below:
var spawn = require('child_process').spawn,
var stream = require('stream');
cmd = spawn('cmd', ['/s', '/c', 'C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild c:\\test.sln'], { stdio: [process.stdin, process.stdout, 'pipe'] });
var customStream = new stream.Writable();
customStream._write = function (data, ...argv) {
console.log('your notation');
process.stderr._write(data, ...argv);
};
cmd.stderr.pipe(customStream);
note that the code use es6
Solution 7 - node.js
I have tried many options above, and they did not work. For npm (and probably node) commands, this works:
const ps = _spawn('npm', ['outdated', '--color=always'], { stdio: 'pipe'});
ps.stdout.pipe(process.stdout);
// Then, you can also ps.stdout.on('data',...) for further processing
The trick is the --color=always
(using Mac OSX with zsh). I did not need to do the FORCE_COLOR.
However, that does not work for all commands, for example ls
does not seem to accept this argument.
Solution 8 - node.js
I was there too. Like said in the thread, there's no colored output because the command you're executing doesn't detect a TTY environment.
If you:
- Don't want to inherit the child stdout
- Don't know which command is going to be executed (then you don't know which of e.g --ansi or --colors can work)
Then you should spawn a PTY from node. You may use node-pty
, but it is a hassle to install, and it doesn't support latest node versions. Instead, I suggest using this node package that I wrote.