Make a script which accept command-line arguments - node.js

What is the correct syntax for running a Node.js script with command-line arguments on Linux or Mac?
To run the script with no arguments, I would simply use the command node stuff.js, but in this case, I'd like to run a script called stuff.js with the arguments "blah", "hee", "woohoo!".

See http://nodejs.org/docs/latest/api/process.html#process_process_argv
In summary you'll run it like
node stuff.js blah hee "whoohoo!"
Then your arguments are available in process.argv

If you want to do more sophisticated stuff, the following modules are really helpful:
yargs by Benjamin Coe
commander by TJ Holowaychuk
vorpal by David Caccavella
nopt by Isaac Schlueter
And for fun
cli-table by Guillermo Rauch
node-multimeter by substack
chalk by Sindre Sorhus

Nomnom is another possible solution.

This simple node module is also helpfull: command-line-args
It allows to define a simple definition:
const optionDefinitions = [
{ name: 'verbose', alias: 'v', type: Boolean },
{ name: 'src', type: String, multiple: true, defaultOption: true },
{ name: 'timeout', alias: 't', type: Number }
]
It validates your options and allows you to access them in a simple way.

The arguments are stored in
process.argv
and to pass the arguments in command line please check below example:
ex. in this example below i have used commander NPM Module.
var args = require('commander')
Options with commander are defined with the .option() method.
The example below parses args and options from process.argv, leaving remaining args as the program.args array which were not consumed by options.
here process.argv is An array containing the command line arguments. The first element will be 'node', the second element will be the name of the JavaScript file. The next elements will be any additional command line arguments
after executing.
function list(val) {
return val.split(',');
}
args.version('0.11.2')
.option('-t, --tag [value]', 'tags to ignore', list, undefined)
.parse(process.argv);
here to take input from command-line, we have to execute .js file with -t and after that arguments separated by comma(,)incase of multiple arguments
ex. : node example.js -t tagname
here i have used list to process multiple command line arguments ,so that we can pass multiple command line arguments
ex. node example.js -t tagname1, tagname2
so after this , all input passed as command line arguments will be available in array named args, so can use this array for your purpose
and
you can read more about it from here:-
https://nodejs.org/docs/latest/api/process.html#process_process_argv
or you can make use of the following modules :
commander:-
https://www.npmjs.com/package/commander
yargs :-
https://www.npmjs.com/package/yargs
vorpal :-
https://www.npmjs.com/package/vorpal

Related

Node.JS reading data from console command

I remember using something before in node.js that would allow me to run a command like
node appname.js text goes here
and then read the "text goes here" part with something like
console.log(console.text)
I can't remember what it is, and can't find it in any searches. Was this a real thing, or just me dreaming?
You can use process.argv to console the input from command line.
If you run below command in terminal/command line:
node appname.js text goes here.
You can print the command line arguments by:
console.log(process.argv)
Output of above console will be:
['node',
'/home/user/path/to/appname.js',
'text',
'goes',
'here' ]
If you dont want first two text, you can use:
console.log(process.argv.slice(2))
Output of above console will be:
['text',
'goes',
'here' ]
Read this link for more info.
Hope this helps you out!!!
Well there is lot's ways/packages around for reading from arguments.
the nodejs process is the base of it so check here
And also as i said lot's of packages there for parsing arguments.
yargs is one of them, minimist is also a populer one as far as i know.
If you don't want t use a package basicly it starts like this:
// inside node file
const args = process.argv.splice(2);
console.log(args);
// we are splice'ing from 2 cause
// process.argv[0] is your node-path
// process.argv[1] is your js file's full path
// Most of the time we are not using those so :)
So hope these would work for you ☺

Wildcards in node child process [duplicate]

I want to execute a command like "doSomething ./myfiles/*.csv" with spawn in node.js. I want to use spawn instead of exec, because it is some kind of watch process and I need the stdout output.
I tried this
var spawn = require('child_process').spawn;
spawn("doSomething", ["./myfiles/*.csv"]);
But then the wildcard *.csv will not interpreted.
Is it not possible to use wildcards when using spawn()? Are there other possibilities to solve this problem?
Thanks
Torben
The * is being expanded by the shell, and for child_process.spawn the arguments are coming through as strings so will never get properly expanded. It's a limitation of spawn. You could try child_process.exec instead, it will allow the shell to expand any wildcards properly:
var exec = require("child_process").exec;
var child = exec("doSomething ./myfiles/*.csv",function (err,stdout,stderr) {
// Handle result
});
If you really need to use spawn for some reason perhaps you could consider expanding the wildcard file pattern yourself in Node with a lib like node-glob before creating the child process?
Update
In the Joyent Node core code we can observe an approach for invoking an arbitrary command in a shell via spawn while retaining full shell wildcard expansion:
https://github.com/joyent/node/blob/937e2e351b2450cf1e9c4d8b3e1a4e2a2def58bb/lib/child_process.js#L589
And here's some pseudo code:
var child;
var cmd = "doSomething ./myfiles/*.csv";
if ('win32' === process.platform) {
child = spawn('cmd.exe', ['/s', '/c', '"' + cmd + '"'],{windowsVerbatimArguments:true} );
} else {
child = spawn('/bin/sh', ['-c', cmd]);
}
Here's the simplest solution:
spawn("doSomething", ["./myfiles/*.csv"], { shell: true });
As #JamieBirch suggested in his comment, the key is telling spawn() to use the shell ({ shell: true }, see the docs), so the wildcard is properly resolved.
What OS are you using? In Unix-family OSs (e.g. Linux, MacOS), programs expect the shell process to expand wildcard filename arguments and pass the expansion in argv[]. In Windows OSs, programs usually expect to have to expand wildcards themselves (though only if they're Windows-native programs; ported Unix-family programs may at most try to run the arguments through a compatibility layer).
Your syntax looks like it's for a Unix-family system. If so, then when you call spawn() you're bypassing shell expansion, and your child process is going to treat dots and asterisks in arguments literally. Try using sh child_process in place of child_process and see if you get better results.

how to escape whitespace in Node-RED exec node command

Situation:
In my Node-RED flow there is a call to another program where I use the exec node.
The arguments are set-up in a function node and passed as the msg.payload to the exec node.
This works fine and returns the expected results as long as the command has no space in it.
Problem:
A customer cannot use the call to the command on his system, because the path tp the installation of the program contains a whitespace.
What I tried and didn't work:
Escaping the whitespace with ^ as read in another question: /opt/path^ toProgram^ directory/program
Escaping the whitespace with \\: /opt/path\\ toProgram\\ directory/program
Quoting the whole string with "": "/opt/path toProgram directory/program"
Quoting the whole string and escaping the whitespace: "/opt/path\\ toProgram\\ directory/program"
Quoting the whole string with '': '/opt/path toProgram directory/program'
Leaving the command line empty/""and combining any of the above points with its arguments to one string (in the function node that sets up the arguments for that exec node) and passing it on as the msg.payload -> input parameters in the exec node config panel. No Success.
What's not the problem:
The program itself works fine, on mine and on the customers system, it's only the path that is different
Other than that specific command string with whitespace, the configuration of the exec node and its msg.payload ( = input parameters or arguments) as well as the "use spawn() instead of exec()?" is fine and works
Request
Is there any other way to escape the whitespace that I'm not aware of so the path to the program can be found? From my understanding the whitespace is interpreted as a separator for the input arguments, which it should be, but not on the command string.
This should be a quick fix in my opinion, however nothing seems to work that usually works in node, js, php or bash.. thanks in advance for any hints and ideas!
Environment:
Node-RED version: v0.15.2 |
Node.js version: v5.12.0 |
Mac OS X 10.11.6 = Darwin 15.6.0 x64 LE
Screenshots
This is the part of the flow:
This config works:
This config does not work:
I've just tested this and option 3 (Quoting the path with "") works fine.
Putting "/home/foo/foo bar/date" in the command section of the exec node executed the binary correctly
After a good nights sleep the solution (at least what I thought at the time) was to adapt the exec node in node-red itself: The original code appended the additional arguments (the ones separated by whitespace) to the command, and then slice the whole string by whitespace into an array (node.cmd is the path to the command with or without whitespace):
before: var arg = node.cmd; arg += " "+msg.payload; arg = arg.match(/(?:[^\s"]+|"[^"]*")+/g);
and the (earlier, incomplete) solution was to prepend the command with the builtin array.unshift(<value>) function to the array after the slice operation, so that the command path with the whitespace is not affected by the array creation:
after: var arg = ""; ...add msg.payload and slice arg string into array.. arg.unshift(node.cmd);
The file can be found at: nodered node 75-exec.js on github, in the lines 46-51
Update to real solution:
After further investigation it was clear, that the Use spawn() instead of exec()? option was the problem: the command part with whitespace in double quotes and using exec() worked fine. And my approach couldn't be used when the command path contained an argument, e.g. in /home/foo bar/date -r 1000.
Following the issue at the official github repository of node-red the command part to the arguments array at the beginning after the slice but instead to have the command path with whitespace in quotes and later unwrapping them, copying the behaviour when exec() is used. He added this line in the original file after line 51: if (/^".*"$/.test(cmd)) { cmd = cmd.slice(1,-1); } and now both spawn() and exec() work the same - credits to him, unfortunately I don't know his username here.

Node js: Executing command line (opening a file)

I am trying to open a file through the command line by using node. I am using child_process.spawn, here is the code
var
process = require('child_process'),
cmd = process.spawn('cmd', ['start','tmp.txt'], {cwd: 'C:\\Users\\testuser\\Node_dev'});
I am expecting the file tmp.txt located in the Node_dev folder to be opened but I am getting the error -
dir error { [Error: spawn ENOENT] code: 'ENONENT', errno: 'ENOENT', syscall: 'spawn'
What am I missing?
Also, what's the difference between child_process.spawn vs child_process.exec for this?
I don't have an explanation for your ENOENT error [update: turns out this was a red herring], but one problem with your command is that you launch cmd.exe without /c, meaning that the shell spawned will (a) stay open and (b) actually ignore the specified command.
As for how the child_process module's methods differ:
.execFile and .exec take a callback that reports a single, buffered result, whereas .spawn provides chunked output via events.
Only .exec passes the command to the platform's default shell, which makes it more convenient, but less efficient.
In your case, you don't care about output returned from the spawned command, and since you need to involve the shell anyway,.exec is the best choice.
On Windows, use of start comes with its own pitfalls:
It is not an executable, but a shell builtin (to put it in Unix terms) - thus, it must be invoked via cmd.exe.
If its 1st argument is a [double-quoted] value with embedded spaces, it is interpreted as a window title rather than a filename argument; thus, to robustly pass a filename argument, you must pass an empty window title as the 1st argument.
Here are invocations that should work on Windows - note that both launch the child process asynchronously and ignore any output from it - all they do is to tell cmd.exe to open the specified file as if a user had opened it in Explorer:
using .exec:
var cpm = require('child_process');
// With .exec, specify the entire shell command as the 1st argument - it is implicitly
// passed to cmd.exe.
// '""' as the 1st argument to `start` is an empty window title that ensures that any
// filename argument with embedded spaces isn't mistaken for a window title.
cpm.exec('start "" "tmp.txt"', {cwd: 'C:\\Users\\testuser\\Node_dev'});
using .execFile or .spawn:
// With .spawn or .execFile, specify `cmd` as the 1st argument, and the shell command
// tokens as an array passed as the 2nd argument.
// Note the /c, which ensures that cmd exits after having executed the specified
// command.
// '""' as the 1st argument to `start` is an empty window title that ensures that any
// filename argument with embedded spaces isn't mistaken for a window title.
cpm.spawn('cmd', [ '/c', 'start', '""', 'tmp.txt' ], {cwd: 'C:\\Users\\testuser\\Node_dev'});
There is a cross-platform module on npm called open that opens files using the OS's default handler that you could use as a guide or just use it as-is.
To do it manually with spawn on Windows though, you'd do something like:
var args = ['/s', '/c', 'start', '', 'tmp.txt'],
opts = { cwd: 'C:\\Users\\testuser\\Node_dev' },
child = child_process.spawn('cmd.exe', args, opts);
child_process.exec() is basically a higher-level wrapper for child_process.spawn() which buffers output and then passes the buffered stdout and stderr output to a callback.
I am using the same, here is my command to run and executable with arguments:
var exec = require('child_process').spawn;
let scanProcess = exec('cmd', [ '/c', 'start', '""', 'feature.exe --version' ], {cwd: 'command_folder'});
I am running this on Azure DevOps in a container running Windows OS.
The above command just doesn't come back, it hangs. Any pointers.

Wildcards in child_process spawn()?

I want to execute a command like "doSomething ./myfiles/*.csv" with spawn in node.js. I want to use spawn instead of exec, because it is some kind of watch process and I need the stdout output.
I tried this
var spawn = require('child_process').spawn;
spawn("doSomething", ["./myfiles/*.csv"]);
But then the wildcard *.csv will not interpreted.
Is it not possible to use wildcards when using spawn()? Are there other possibilities to solve this problem?
Thanks
Torben
The * is being expanded by the shell, and for child_process.spawn the arguments are coming through as strings so will never get properly expanded. It's a limitation of spawn. You could try child_process.exec instead, it will allow the shell to expand any wildcards properly:
var exec = require("child_process").exec;
var child = exec("doSomething ./myfiles/*.csv",function (err,stdout,stderr) {
// Handle result
});
If you really need to use spawn for some reason perhaps you could consider expanding the wildcard file pattern yourself in Node with a lib like node-glob before creating the child process?
Update
In the Joyent Node core code we can observe an approach for invoking an arbitrary command in a shell via spawn while retaining full shell wildcard expansion:
https://github.com/joyent/node/blob/937e2e351b2450cf1e9c4d8b3e1a4e2a2def58bb/lib/child_process.js#L589
And here's some pseudo code:
var child;
var cmd = "doSomething ./myfiles/*.csv";
if ('win32' === process.platform) {
child = spawn('cmd.exe', ['/s', '/c', '"' + cmd + '"'],{windowsVerbatimArguments:true} );
} else {
child = spawn('/bin/sh', ['-c', cmd]);
}
Here's the simplest solution:
spawn("doSomething", ["./myfiles/*.csv"], { shell: true });
As #JamieBirch suggested in his comment, the key is telling spawn() to use the shell ({ shell: true }, see the docs), so the wildcard is properly resolved.
What OS are you using? In Unix-family OSs (e.g. Linux, MacOS), programs expect the shell process to expand wildcard filename arguments and pass the expansion in argv[]. In Windows OSs, programs usually expect to have to expand wildcards themselves (though only if they're Windows-native programs; ported Unix-family programs may at most try to run the arguments through a compatibility layer).
Your syntax looks like it's for a Unix-family system. If so, then when you call spawn() you're bypassing shell expansion, and your child process is going to treat dots and asterisks in arguments literally. Try using sh child_process in place of child_process and see if you get better results.

Resources