node.js: console.log from child_process - node.js

In node, I am running a perl script using child_process, and console.log in the callback seems to be behaving strangely.
child = exec("perl " + validationScript,
{cwd: myDir},
function(err, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
return cb(err);
});
stdout is printing correctly, but the stderr print statement is not executing. (If I comment out the stdout print, then stderr is printed correctly). So some buffering problem? How can I make them print correctly?
I am new to asynchronous programming, so sorry if this question is too basic.

have you tried it without return? The following code works for me. aa provokes an error and I have something on the stderr, if I only use ls I'll get no error but a correct stdout.
child = exec('ls aa',
function(err, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
cb(err);
});
function cb(data) {
console.log(data);
}

Related

Suppressing STDOUT with node child_process

I am running the following code:
var exec = require('child_process').exec;
var command = "security set-key-partition-list -S apple-tool:,apple: -s -k password /path/to/keychain/login.keychain-db";
exec(serverConfig.securityCall, function (error, stdout, stderr) {
if (error !== null) {
console.log('exec error: ' + error);
console.log('STDERR: ' + stderr);
console.log('STDOUT: ' + stdout);
}
});
I get the error: exec error: Error: stdout maxBuffer exceeded.
Is there a way to suppress the stdout? I don't need it.
I saw this post: Stdout buffer issue using node child_process
So, I changed it to a spawn
var spawn = require('child_process').spawn;
var child = spawn('security', ['set-key-partition-list', '-S apple-tool:,apple: -s -k password /path/to/keychain/login.keychain-db'], {stdio:['ignore', 'ignore', 'pipe']});
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
stderr = 'stderr: ' + data
});
child.on('close', function (code) {
console.log('child process exited with code ' + code);
if (!code) { //0 = success 1= error
console.log("SUCCESS");
} else {
console.log('STDERR: ' + stderr);
}
});
but I get this error:
stderr: password to unlock default: security: SecKeychainItemSetAccessWithPassword: The user name or passphrase you entered is not correct.
If I run this from command line it works, so i know my password is correct. (password and path to keychain have been redacted for security purposes).
How can I get this to work with spawn or exec?
The error you get is coming from your security application, not from Node. There is a tricky part of using spawn. Every single option should be a separate array element.
So this array element should be separated to multiple elements
'-S apple-tool:,apple: -s -k password /path/to/keychain/login.keychain-db'
Something like
['-S', 'apple-tool:,apple:', '-s', '-k', 'password', '/path/to/keychain/login.keychain-db']
Honestly I don't understand why it is not explained well in the documentation.

node child_process gives valid output in stderr for mongodump

I'm executing mongodump command from nodejs child_process.
I have tried both exec and spawn, but the progress printed by mongodump is hitting the data event of stderr instead of stdout
var exec = require('child_process').exec,
ls = exec('mongodump --gzip --archive="/home/test-machine/test.archive" --db myDB');
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());
});
The mongodump is not crashing, or throwing any error, its executing as it should. But somehow nodejs is treating the output as stderr
mongodump writes log messages to stderr, which isn't very uncommon, although it makes parsing the output for errors a bit harder because you need to manually filter out the error messages.

Execute bash command in Node.js and get exit code

I can run a bash command in node.js like so:
var sys = require('sys')
var exec = require('child_process').exec;
function puts(error, stdout, stderr) { sys.puts(stdout) }
exec("ls -la", function(err, stdout, stderr) {
console.log(stdout);
});
How do I get the exit code of that command (ls -la in this example)? I've tried running
exec("ls -la", function(err, stdout, stderr) {
exec("echo $?", function(err, stdout, stderr) {
console.log(stdout);
});
});
This somehow always returns 0 regardless of the the exit code of the previous command though. What am I missing?
Those 2 commands are running in separate shells.
To get the code, you should be able to check err.code in your callback.
If that doesn't work, you need to add an exit event handler
e.g.
dir = exec("ls -la", function(err, stdout, stderr) {
if (err) {
// should have err.code here?
}
console.log(stdout);
});
dir.on('exit', function (code) {
// exit code is code
});
From the docs:
If a callback function is provided, it is called with the arguments (error, stdout, stderr). On success, error will be null. On error, error will be an instance of Error. The error.code property will be the exit code of the child process while error.signal will be set to the signal that terminated the process. Any exit code other than 0 is considered to be an error.
So:
exec('...', function(error, stdout, stderr) {
if (error) {
console.log(error.code);
}
});
Should work.
child_process.spawnSync()
This function exposes the nicest sync interface: https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options
Example:
#!/usr/bin/env node
const child_process = require('child_process');
let out;
out = child_process.spawnSync('true');
console.log('status: ' + out.status);
console.log('stdout: ' + out.stdout.toString('utf8'));
console.log('stderr: ' + out.stderr.toString('utf8'));
console.log();
out = child_process.spawnSync('false');
console.log('status: ' + out.status);
console.log('stdout: ' + out.stdout.toString('utf8'));
console.log('stderr: ' + out.stderr.toString('utf8'));
console.log();
out = child_process.spawnSync('echo', ['abc']);
console.log('status: ' + out.status);
console.log('stdout: ' + out.stdout.toString('utf8'));
console.log('stderr: ' + out.stderr.toString('utf8'));
console.log();
Output:
status: 0
stdout:
stderr:
status: 1
stdout:
stderr:
status: 0
stdout: abc
stderr:
Tested in Node.js v10.15.1, Ubuntu 19.10.
If anyone is looking for an await/Promise version:
const exec = require('util').promisify(require('child_process').exec);
let out = await exec(`echo hello`).catch(e => e);
console.log(out.stdout); // outputs "hello"
console.log(out.code); // Note: `out.code` is *undefined* if successful (instead of 0).
If the command is successful, then the it'll output an object like {stderr, stdout}. If it has a non-zero exit code, then it'll output an error object with {stderr, stdout, code, killed, signal, cmd} and the usual JavaScript Error object properties like message and stack.
In node documentation i found this information for the callback function:
On success, error will be null. On error, error will be an instance of Error. The error.code property will be the exit code of the child process while error.signal will be set to the signal that terminated the process. Any exit code other than 0 is considered to be an error.

Execute multiple shell commands in Node.js

I want to execute multiple Shell commands from a node.js application consecutively. In my case, exec(command1 & command2) does not work as it should. It works for simple commands like ls and pwd, but I need to start a server and then execute special commands on it and there, it only executes the very first command and nothing more. When I work on my command-line interface, I just type in one command after the other and I need a facility to execute them in the same manner, but automatically starting from a node.js application - and all of them in the same process!
You could use child_process module to achieve that.
Here's an example code to demonstrate the usage
var child_process = require('child_process');
var task1 = child_process.exec('node --version', function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
var task2 = child_process.exec('npm --version', function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});

node.js mplayer fifo control

I am trying to create an webscket control wrapper for mplayer on beaglebone with node.js.
A glimpse of my websocket server looks lke this:
io.sockets.on('connection', function (socket)
{
SaveToLog('Client ' + clientAddress + ' connected.');
/* Function used to control the LEDs according to HTML file */
allClients.push(socket);
socket.on('miro_server', function (device, command)
{
SaveToLog(device + ' ' + command);
switch (device)
{
case 'mplayerStatus':
if(command == 'PLAYSELECTED')
{
ls = childProcess.exec('mplayer -slave -quiet -input file=/home/root/.mplayer/mplayer_fifo /home/root/agalloch.mp3',
function (error, stdout, stderr)
{
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null)
{
console.log('exec error: ' + error);
}
});
ls.on('exit', function (code)
{
console.log('Child process exited with exit code '+code);
});
}
else /* PAUSE */
{
childProcess.exec('echo "pause" > /home/root/.mplayer/mplayer_fifo',
function (error, stdout, stderr)
{
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null)
{
console.log('exec error: ' + error);
}
});
}
break;
}
});
});
The mplayer process starts correctly and I can hear music from the speakers, but the problem is that I cannot send any commands to the mplayer process via the selected fifo.
When I try the same commands in the linux terminal, it works just fine, so I presume it has something to do with the node.js process exec part.
I do not have much experience with linux or node.js, and most of the code I've written is based on code examples and tutorials.
Can anyone explain what is going on and why I cannot send playback command via fifo to the mplayer process using node.js?
Thank you.
you need to add new line to the echo command
'echo "pause" > /home/root/.mplayer/mplayer_fifo\n'
I tried this on rpi and bbb and it works info here http://sonnycruz.blogspot.com

Resources