I have a NodeJS app that needs to execute some commands using spawn
, I'm reading the output for later processing using readline
which works flawlessly.
But I also need to get the color of the text, For example: when executing another Node.js
script that uses chalk
module.
How can this be accomplished ?
This is my code so far:
const spawn = require('child_process').spawn;
const readline = require('readline');
let myCommand = spawn(<command>, [<args...>], { cwd: dirPath });
readline.createInterface({
input : myCommand.stdout,
terminal : true
}).on('line', (line) => handleOutput(myCommand.pid, line));
readline.createInterface({
input : myCommand.stderr,
terminal : true
}).on('line', (line) => handleErrorOutput(myCommand.pid, line));
myCommand.on('exit', (code) => {
// Do more stuff ..
});
Amr K. Aly's answer does work but when executing an external NodeJS
script it return null color.
My code (index.js) :
const spawn = require('child_process').spawn;
const readline = require('readline');
let myCommand = spawn('node', ['cmd.js']);
readline.createInterface({
input: myCommand.stdout,
terminal: true
}).on('line', (line) => handleOutput(myCommand.pid, line));
readline.createInterface({
input: myCommand.stderr,
terminal: true
}).on('line', (line) => handleErrorOutput(myCommand.pid, line));
myCommand.on('exit', (code) => {
// Do more stuff ..
});
function handleErrorOutput(obj, obj2) {}
function handleOutput(obj, line, a, b, c) {
//PRINT TEXT WITH ANSI FORMATING
console.log(line);
//REGEX PATTERN TO EXTRACT COLOR
var options = Object.assign({
onlyFirst: false
});
const pattern = [
'[\\u001B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
'(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
].join('|');
var regex = new RegExp(pattern, options.onlyFirst ? undefined : 'g');
var ansiColor = (line.match(regex));
//PRINT EXTRACTED ANSI
console.log("ANSI COLOR CODE :");
console.log(ansiColor);
}
cmd.js :
const chalk = require('chalk');
console.log(chalk.blue('Blue Hello world!'));
console.log(chalk.green('green Hello world!'));
console.log(chalk.red('red Hello world!'));
my results :
Issue:
You can not see the colors when printing back the text stream you read because you have set the terminal
option in createInterface to true
. This causes createInterface() not to return ANSI/VT100 encoding.
Solution:
The terminal
option needs to be set to false
so the text would be encoded with ANSI/VT100 From Nodejs Docs: terminal <boolean> true if the input and output streams should be treated like a TTY, and have ANSI/VT100 escape codes written to it. Default: checking isTTY on the output stream upon instantiation.
terminal <boolean> true if the input and output streams should be treated like a TTY, and have ANSI/VT100 escape codes written to it. Default: checking isTTY on the output stream upon instantiation.
See readline.createInterface(options) documentation
readline.createInterface({
input: myCommand.stdout,
terminal: true//<== NEEDS TO BE SET TO FALSE
}).on('line', (line) => handleOutput(myCommand.pid, line));
After setting terminal
to false
, the returned text will be ANSI/VT100 encoded. You'll then need to extract the ANSI/VT100 encoding related to colors and change it to whatever color format you need.
See modified code and output below with added regex to extract ANSI color codes. You need to add your own logic to process the ANSI escaped colors.
const spawn = require('child_process').spawn;
const readline = require('readline');
const chalk = require('chalk');
//Testing on windows 10
let myCommand = spawn(process.env.comspec, ['/c', 'echo ' + chalk.red('Hello world!'), ], {
// cwd: dirPath
});
readline.createInterface({
input: myCommand.stdout,
terminal: false
}).on('line', (line) => handleOutput(myCommand.pid, line));
readline.createInterface({
input: myCommand.stderr,
terminal: false
}).on('line', (line) => handleErrorOutput(myCommand.pid, line));
myCommand.on('exit', (code) => {
// Do more stuff ..
});
function handleErrorOutput(obj, obj2) {}
function handleOutput(obj, line) {
//PRINT TEXT WITH ANSI FORMATING
console.log(line);
//REGEX PATTERN TO EXTRACT COLOR
var options = Object.assign({
onlyFirst: false
});
const pattern = [
'[\\u001B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
'(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
].join('|');
var regex = new RegExp(pattern, options.onlyFirst ? undefined : 'g');
var ansiColor = (line.match(regex));
//PRINT EXTRACTED ANSI
console.log("ANSI COLOR CODE :");
console.log(ansiColor);
}
Output for code above:
EDIT:
Chalk detects automatically if you're writing to a TTY or the terminal doesn't support colors and disables the coloring. You can force it by setting an environment variable FORCE_COLOR=1
or by passing a --color
as an argument.
If you change your code to the line from the snippet below, Chalk should add the styling correctly.
let myCommand = spawn('node', ['test.js', '--color', ], {
});
Output:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.