How do use nodejs childprocess exec to run the unix diff command? - node.js

I need to use node to generate diffs of some files. I have tried the diff npm package, and while that works great it is much less performant than the version of diff you will find in /usr/bin/.
When I try to use exec to run the diff command it always errors.
var childProcess = require('child_process');
var cmd = "diff /path/to/file1.txt /path/to/file2.txt";
childProcess.exec(cmd, (error, stdout, stderr) => {
if(error) {
console.log(error);
} else {
console.log(stdout);
}
});
The output:
{ [Error: Command failed: /bin/sh -c diff /path/to/file1.txt /path/to/file2.txt
]
killed: false,
code: 1,
signal: null,
cmd: '/bin/sh -c diff /path/to/file1.txt /path/to/file2.txt' }
If I run the command on the command line myself it works fine.
I've tried running /usr/bin/diff instead of just diff.
I've tried various different forms of quoting things.
Every other command I have tried, using the exact same files, has worked. cat, wc, etc.
Any thoughts?

Welp, I am answering my own question.
The diff command returns a failure exit code if it finds a difference. Therefore the console.log(stdout) call was never being reached.
If I ignore the error, everything works.
var childProcess = require('child_process');
var cmd = "diff /path/to/file1.txt /path/to/file2.txt";
childProcess.exec(cmd, (error, stdout, stderr) => {
console.log(stdout);
});
works like a charm.

Related

Why do nodejs exec/spawn not show any output for bash 'history' command?

I am running this on Ubuntu and have tried many variations of exec/spawn functions (and their sync counterparts) and none of them can show me an output for bash 'history' command. One scenario is following:
const { spawnSync} = require('child_process');
const child = spawnSync('history', { shell: "/bin/bash" });
console.log('error: ', child.error);
console.log('stdout: ', child.stdout.toString());
console.log('stderr: ', child.stderr);
It does not show any errors and output is empty. I think this question has more to do with 'specialty' or category of the history command than nodejs's function since they work fine for normal commands like ls, pwd, whoami, etc work fine. I have looked at my .bash_history file and its filled with history so that's not the issue.
Another problem that might be similar is ll command also fails even though I have set bash as shell. But for ll, it does return an error:
/bin/bash: ll: command not found
Just to be sure, I tried running ll command in bash it worked just fine. What am I missing here?
edit: I have done some more testing it seems more like a bash thing than a node thing. When I simply write the history command, bash prints results but when I do bash -c history, it does not show any output but also no error.
.
You need to subscribe to messages from child process
child.on('error', (err) => {
});
child.stderr.on('data', (data) => {
});
child.on('exit', (code, signal) => {
});

Node js - how to execute two windows commands in sequence and get the output

I am trying to execute two windows commands in sequence and get the result of the later one. Something like:
cd ${directory}
sfdx force:source:convert -d outputTmp/ --json
I have browsed and tried a bunch of third-party libraries, like node-cmd. But so far I haven't got any luck yet. As in node-cmd example:
cmd.get(
`cd ${directory}
sfdx force:source:convert -d outputTmp/ --json`,
function(err, data, stderr) {
This works very well on my macOS machine. But on Windows it tends to execute only the first command.
Is there anyway I can resolve this issue? Even some walk around for just cd {directory} + real command can be really helpful
You can try this:
const exec = require('child_process').exec;
exec(`cd dir
sfdx force:source:convert -d outputTmp/ --json`, (err, stdout, stderr) => {
if (err) {
// node couldn't execute the command
return;
}
console.log(stdout);
});
or by using && without backticks:
const exec = require('child_process').exec;
exec('cd dir && sfdx force:source:convert -d outputTmp/ --json', (err, stdout, stderr) => {
if (err) {
// node couldn't execute the command
return;
}
console.log(stdout);
});

How to run shell script file using nodejs?

I need to run a shell script file using nodeJS that executes a set of Cassandra DB commands. Can anybody please help me on this.
inside db.sh file:
create keyspace dummy with replication = {'class':'SimpleStrategy','replication_factor':3}
create table dummy (userhandle text, email text primary key , name text,profilepic)
You could use "child process" module of nodejs to execute any shell commands or scripts with in nodejs. Let me show you with an example, I am running a shell script(hi.sh) with in nodejs.
hi.sh
echo "Hi There!"
node_program.js
const { exec } = require('child_process');
var yourscript = exec('sh hi.sh',
(error, stdout, stderr) => {
console.log(stdout);
console.log(stderr);
if (error !== null) {
console.log(`exec error: ${error}`);
}
});
Here, when I run the nodejs file, it will execute the shell file and the output would be:
Run
node node_program.js
output
Hi There!
You can execute any script just by mentioning the shell command or shell script in exec callback.
You can execute any shell command using the shelljs module
const shell = require('shelljs')
shell.exec('./path_to_your_file')
you can go:
var cp = require('child_process');
and then:
cp.exec('./myScript.sh', function(err, stdout, stderr) {
// handle err, stdout, stderr
});
to run a command in your $SHELL.
Or go
cp.spawn('./myScript.sh', [args], function(err, stdout, stderr) {
// handle err, stdout, stderr
});
to run a file WITHOUT a shell.
Or go
cp.execFile();
which is the same as cp.exec() but doesn't look in the $PATH.
You can also go
cp.fork('myJS.js', function(err, stdout, stderr) {
// handle err, stdout, stderr
});
to run a javascript file with node.js, but in a child process (for big programs).
EDIT
You might also have to access stdin and stdout with event listeners. e.g.:
var child = cp.spawn('./myScript.sh', [args]);
child.stdout.on('data', function(data) {
// handle stdout as `data`
});
Also, you can use shelljs plugin.
It's easy and it's cross-platform.
Install command:
npm install [-g] shelljs
What is shellJS
ShellJS is a portable (Windows/Linux/OS X) implementation of Unix
shell commands on top of the Node.js API. You can use it to eliminate
your shell script's dependency on Unix while still keeping its
familiar and powerful commands. You can also install it globally so
you can run it from outside Node projects - say goodbye to those
gnarly Bash scripts!
An example of how it works:
var shell = require('shelljs');
if (!shell.which('git')) {
shell.echo('Sorry, this script requires git');
shell.exit(1);
}
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');
// Run external tool synchronously
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
shell.echo('Error: Git commit failed');
shell.exit(1);
}
Also, you can use from the command line:
$ shx mkdir -p foo
$ shx touch foo/bar.txt
$ shx rm -rf foo

Using bash with Node.js child_process using the shell option fails

The child process api can be used to execute shell script in node.js.
Im using the child_process.exec(command[, options], callback) function
as an option the user of exec can set the shell: '/path/to/shell' field to select the shell to be used. (Defaults to '/bin/sh')
Setting options to {shell: '/bin/bash'} does not make exec runt the command with bash.
I have verified this by issuing the command "echo $0" which prints "/bin/sh".
How can I use bash with child_process.exec through the shell option?
(My goal is to make use of my path definitions in bashrc, now when i try to use grunt the binary cannot be found. Setting the cwd, current working directory in the options dictionary works as expected)
----------------- UPDATE, example
'use strict';
var cp = require('child_process');
cp.exec('echo $0', { shell: '/bin/bash' }, function(err, stdout, stderr){
if(err){
console.log(err);
console.log(stderr);
}
console.log(stdout);
});
Output:
/bin/sh
which bash
prints:
/bin/bash
Might be in your setup or passing options incorrectly in your code. Since you didn't post your code, it's tricky to tell. But I was able to do the following and it worked (using node 4.1.1):
"use strict";
const exec = require('child_process').exec
let child = exec('time',{shell: '/bin/bash'}, (err, stdout, stderr) => {
console.log('this is with bash',stdout, stderr)
})
let child2 = exec('time',{shell: '/bin/sh'}, (err, stdout, stderr) => {
console.log('This is with sh', stdout, stderr)
})
The output will be:
this is with bash
real 0m0.000s
user 0m0.000s
sys 0m0.000s
This is with sh /bin/sh: 1: time: not found
I used time as the command since it's one that bash has and sh does not. I hope this helps!

Node js Child_process not returning stdout

Not sure why this does not work, if I run a simple command such as cmd='ls -all' then I get the output back, but when I use this to run a command which takes some time to complete I don't get anything at all returned.
In this example, I am using lftp to mirror some folders and want to get the reply, if I run the command from the terminal then of course I see the output, but using child process I get nothing:
var childProcess = require('child_process');
var cmd = 'lftp sftp://user:password#somehost -e "mirror -R --delete --parallel=5 /usr/share/scripts/ /volumes/folders/usr/share/;bye"';
childProcess.exec(cmd, function (error, stdout, stderr) {
console.log('stdout:'+stdout);
console.log('stderr:'+stderr);
console.log('error:'+error);
});
I also tried the spawn method, nothing returned from that either:
var spawn = require('child_process').spawn;
var lftp = spawn('lftp',['sftp://user:password#somehost', '-e "mirror -R --delete --parallel=5 /usr/share/scripts/ /volumes/folders/usr/share/;bye"']);
lftp.stdout.on('data', function(data) {
console.log(data.toString());
});
I think the problem is that lftp buffers its output.
To get around that you'll need to use unbuffer (http://expect.sourceforge.net/example/unbuffer.man.html) to send the output directly to stdout.

Resources