I want to use child_process.spawn to execute a windows exe file and catch it's output.
When I use command line to run a thirdparty exe file (says A.exe), it will print some logs to the cmd window. Like this:
C:\> A.exe
some outputs...
some more outputs...
However, when I spawn it in node.js, using this
import childProcess from 'child_process';
const cp = childProcess.spawn('A.exe');
cp.stdout.on('data', data => console.log(`stdout: ${data}`));
cp.stderr.on('data', data => console.log(`stderr: ${data}`));
There is no outputs at all.
I think the outputs of A.exe is not to the stdout (so I can never get data by listening stdout), but I don't know how it print logs when running from command line.
Any help would be greatly appreciated.
On Unix-type operating systems (Unix, Linux, macOS) child_process.execFile() can be more efficient because it does not spawn a shell. On Windows, however, .bat and .cmd files are not executable on their own without a terminal, and therefore cannot be launched using child_process.execFile(). When running on Windows, .bat and .cmd files can be invoked using child_process.spawn() with the shell option set, with child_process.exec(), or by spawning cmd.exe and passing the .bat or .cmd file as an argument (which is what the shell option and child_process.exec() do). In any case, if the script filename contains spaces it needs to be quoted.
// On Windows Only ...
const { spawn } = require('child_process');
const bat = spawn('cmd.exe', ['/c', 'my.bat']);
bat.stdout.on('data', (data) => {
console.log(data.toString());
});
bat.stderr.on('data', (data) => {
console.log(data.toString());
});
bat.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});
Maybe give this approach a go:
var childProcess = require('child_process');
childProcess.exec('A.exe', function(error, stdout, stderr) {
if (error != null) {
console.log('error occurred: ' + error);
} else {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
}
});
// OR
var cp = childProcess.spawn('A.exe');
cp.stdout.on('data', (data) => {
console.log('stdout: ' + data.toString());
});
cp.stderr.on('data', (data) => {
console.log('stderr: ' + data.toString());
});
Related
I've been able to successfully run commands using the exec() command. However, I'd like to leave a process running and continue to run commands on the open process, then close on app exit. Take this generic code:
const { exec } = require("child_process");
exec("XR_Command -i 192.168.0.100 -f /ch/01/on | kill", (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
I would like to keep the XR_Command process active so that I can issue commands to the active process. So, basically I would like to do this:
> XR_Command -i 192.168.0.100
> /ch/01/on
> /ch/02/on
> /ch/03/on
I cannot for the life of me figure out how to make this function properly by referencing the existing child process. Thanks!
Okay, so after a day I figured out two main problems I was running in to, here is my working code:
const { spawn } = require('child_process');
let Command = spawn('X_Control', ['-i', '192.168.0.1']);
Command.stdout.pipe(process.stdout);
Command.stderr.pipe(process.stderr);
Command.stdin.write('some command\n');
Command.on('error', function(err) {
console.error(err);
});
Command.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
Command.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
Issue 1: My application command was X_Control -i 192.168.0.1, every space needs to be quoted separately as Command = spawn('X_Control', ['-i', '192.168.0.1']); This took me a while to track down.
Issue 2: Command.stdin.write('some command\n'); is how I execute commands on my running application, and it must be followed by \n in order to execute the command.
I am looking to spawn an echo process to write some text to a "file".
*The fs package is off limits because the "file" is a communication pathway for a linux driver.
Below is my code to just see if I can get an echo process working with writing to a normal file however the spawn doesn't appear to like the > flag. Any ideas?
var spawn = require('child_process').spawn;
echo = spawn('echo', ["test", ">", __dirname+"/test.txt"]);
echo.on('error', function (err) {
console.log('ls error', err);
});
echo.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
echo.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
echo.on('close', function (code) {
console.log('child process exited with code ' + code);
});
Right now I just get the following output with no written file:
stdout: test > <*PATH*>/test.txt
child process exited with code 0
I ended up just creating a bash file (echo-test.sh) with the following contents:
echo "test" > <*PATH*>/test.txt
and executed in node like such:
echo = spawn('bash', [__dirname+"/echo-test.sh"]);
I have an Express Node.js application, but I want to run python code (send data and receive results)
but when I'm testing it using postman still loading and I don't have any response.
my node.js code
router.get('/name', callName);
function callName(req, res) {
var exec = require("child_process").exec;
var process = exec('python',["./hello.py",
req.query.firstname,
req.query.lastname
] );
process.stdout.on('data', function(error,data) {
console.log('stderr: ', error);
res.send(data.toString());
} )
}
python code
import sys
# Takes first name and last name via command
# line arguments and then display them
print("Output from Python")
print("First name: " + sys.argv[1])
print("Last name: " + sys.argv[2])
# Save the script as hello.py
thank you #nijm I found the solution
first The child_process.exec method doesn't accept the command arguments as an array (like child_process.spawn does).
second,
u must have python installed on ur machine.
third
u must have python file in a public folder (in my case uploads folder)
all these steps don't mention in any tutorial or an example about How to call a Python function from Node.js
at the end of the day, my code is
router.get('/name', callName);
function callName(req, res) {
var exec = require("child_process").exec;
exec(`python uploads/hello.py ${req.query.firstname} ${req.query.lastname}`, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
});
}
python code
import sys
# Takes first name and last name via command
# line arguments and then display them
print("Output from Python")
print("First name: " + sys.argv[1])
print("Last name: " + sys.argv[2])
# Save the script as hello.py
The child_process.exec method doesn't accept the command arguments as an array (like child_process.spawn does), try this (untested):
var exec = require("child_process").exec;
exec(`python ./hello.py ${req.query.firstname} ${req.query.lastname}`, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
});
I'm trying to work with Child Spawn (not working) instead of Exec (working). My Exec code provides me with console output, I see nothing if I run my child spawn code, how can I get console output using Child Spawn:
Here is my working exec code:
var exec = require('child_process').exec,
child;
child = exec('myProgram --version', {},
function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
child.stdout.on('data', function(data) {
console.log(data.toString());
});
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
Here is my non-working attempt at using spawn:
var spawn = require('child_process').spawn;
var spawnchild = spawn('myProgram', ['--version']);
spawnchild.stdout.on('data', function(data) {
console.log('stdout: ' + data);
});
spawnchild.stderr.on('data', function(data) {
console.log('stdout: ' + data);
});
If you add a 'close' event handler for spawnchild, you will see a non-zero exit code. The reason for this is that the first argument for spawn() differs from that of exec(). exec() takes the full command line string, whereas spawn() has just the program name/path for the first argument and the second argument is an array of command line arguments passed to that program.
So in your particular case, you'd use:
var spawnchild = spawn('myProgram', ['--version']);
I have this simple script :
var exec = require('child_process').exec;
exec('coffee -cw my_file.coffee', function(error, stdout, stderr) {
console.log(stdout);
});
where I simply execute a command to compile a coffee-script file. But stdout never get displayed in the console, because the command never ends (because of the -w option of coffee).
If I execute the command directly from the console I get message like this :
18:05:59 - compiled my_file.coffee
My question is : is it possible to display these messages with the node.js exec ? If yes how ? !
Thanks
Don't use exec. Use spawn which is an EventEmmiter object. Then you can listen to stdout/stderr events (spawn.stdout.on('data',callback..)) as they happen.
From NodeJS documentation:
var spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data.toString());
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data.toString());
});
ls.on('exit', function (code) {
console.log('child process exited with code ' + code.toString());
});
exec buffers the output and usually returns it when the command has finished executing.
exec will also return a ChildProcess object that is an EventEmitter.
var exec = require('child_process').exec;
var coffeeProcess = exec('coffee -cw my_file.coffee');
coffeeProcess.stdout.on('data', function(data) {
console.log(data);
});
OR pipe the child process's stdout to the main stdout.
coffeeProcess.stdout.pipe(process.stdout);
OR inherit stdio using spawn
spawn('coffee -cw my_file.coffee', { stdio: 'inherit' });
There are already several answers however none of them mention the best (and easiest) way to do this, which is using spawn and the { stdio: 'inherit' } option. It seems to produce the most accurate output, for example when displaying the progress information from a git clone.
Simply do this:
var spawn = require('child_process').spawn;
spawn('coffee', ['-cw', 'my_file.coffee'], { stdio: 'inherit' });
Credit to #MorganTouvereyQuilling for pointing this out in this comment.
Inspired by Nathanael Smith's answer and Eric Freese's comment, it could be as simple as:
var exec = require('child_process').exec;
exec('coffee -cw my_file.coffee').stdout.pipe(process.stdout);
I'd just like to add that one small issue with outputting the buffer strings from a spawned process with console.log() is that it adds newlines, which can spread your spawned process output over additional lines. If you output stdout or stderr with process.stdout.write() instead of console.log(), then you'll get the console output from the spawned process 'as is'.
I saw that solution here:
Node.js: printing to console without a trailing newline?
Hope that helps someone using the solution above (which is a great one for live output, even if it is from the documentation).
I have found it helpful to add a custom exec script to my utilities that do this.
utilities.js
const { exec } = require('child_process')
module.exports.exec = (command) => {
const process = exec(command)
process.stdout.on('data', (data) => {
console.log('stdout: ' + data.toString())
})
process.stderr.on('data', (data) => {
console.log('stderr: ' + data.toString())
})
process.on('exit', (code) => {
console.log('child process exited with code ' + code.toString())
})
}
app.js
const { exec } = require('./utilities.js')
exec('coffee -cw my_file.coffee')
After reviewing all the other answers, I ended up with this:
function oldSchoolMakeBuild(cb) {
var makeProcess = exec('make -C ./oldSchoolMakeBuild',
function (error, stdout, stderr) {
stderr && console.error(stderr);
cb(error);
});
makeProcess.stdout.on('data', function(data) {
process.stdout.write('oldSchoolMakeBuild: '+ data);
});
}
Sometimes data will be multiple lines, so the oldSchoolMakeBuild header will appear once for multiple lines. But this didn't bother me enough to change it.
child_process.spawn returns an object with stdout and stderr streams.
You can tap on the stdout stream to read data that the child process sends back to Node. stdout being a stream has the "data", "end", and other events that streams have. spawn is best used to when you want the child process to return a large amount of data to Node - image processing, reading binary data etc.
so you can solve your problem using child_process.spawn as used below.
var spawn = require('child_process').spawn,
ls = spawn('coffee -cw my_file.coffee');
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data.toString());
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data.toString());
});
ls.on('exit', function (code) {
console.log('code ' + code.toString());
});
Here is an async helper function written in typescript that seems to do the trick for me. I guess this will not work for long-lived processes but still might be handy for someone?
import * as child_process from "child_process";
private async spawn(command: string, args: string[]): Promise<{code: number | null, result: string}> {
return new Promise((resolve, reject) => {
const spawn = child_process.spawn(command, args)
let result: string
spawn.stdout.on('data', (data: any) => {
if (result) {
reject(Error('Helper function does not work for long lived proccess'))
}
result = data.toString()
})
spawn.stderr.on('data', (error: any) => {
reject(Error(error.toString()))
})
spawn.on('exit', code => {
resolve({code, result})
})
})
}