Writing Command Line Scripts in Node.js

I was new to node.js 4 month ago and my main programming language was Python and C. I was motivated to try node.js by the regex-dna benchmark that shows JavaScript V8 is about 7 times faster than Python 3, and even faster than C implementation.

Jack Franklin’s article, “Writing Command Line Tools with Node” was very helpful for me. The article shows that npm and package.json play an important role in running environment independent of OS, the importance of first line, basic command line argument processing and the way to invoke other commands.

In this post, I would like to share more tips to write scripts in node.js, JavaScript.

Arguments with options and values

Although process.argv is enough to process command line arguments, sometimes command line argument parser, such as getopt in C, argparse in Python is needed for productivity and usability, especially for processing options.

commander.js is perfect for this case. Just writing a help text for options as follows, make the parser works.

1
2
3
4
5
6
7
8
9
var program = require('commander');
program
.option('-b, --boolean', 'Boolean option')
.option('-k, --key [value]', 'Key=value option')
.parse(process.argv);

console.log('Boolean:', program.boolean);
console.log('Key =', program.key);
console.log('Rest arguments:', program.args);

There are alternatives for command line argument parsing:

  • minimist: Small module that returns compact JavaScript object as the result of argument parsing.
  • cli: A toolkit for command line apps that contains several utilities including argument parser.

Detecting the script is called in command line

A script can be used by another script. But, running another node.js script through child_prcess.exec is somewhat hilarious. The best soultion would be import the script through require. But, we want the script works as the command also.

In Python, the folling idiom was used for a file that is used for both command to run and module to import. The main function will not be executed if it is imported as module.

1
2
if __name__ == "__main__":
main()

For example, SimpleHTTPServer module can be imported, but it can be run as simple http server by running python <path_to>/SimpleHTTPServer.py or python -m SimpleHTTPServer.

Similar idiom can be applied to node.js as follows. This is a part of node.js specification since node.js 0.4.8.

1
2
3
if (require.main === module) {
main();
}

Synchronous I/O

The most frustrating feature of node.js would be asynchronous, non-blocking I/O especially for script writers in shell, python, etc. Since node 0.12, there exists synchronous API such as child_prcess.execSync and fs.*Sync. Therefore you may write the scripts as you did in shell or python. But, since the virtue of node.js is fast from asynchronous I/O, I recommend to try asynchronous features of node.js if you have enough time.