Writing Command Line Tools with Node
Back in August 2012 I wrote a post on building a command line tool in NodeJS. That post is now over two years old and plenty has changed, hence I thought it worth writing a new post building the same tool, showing how I'd do it now.
We're going to build the same tool, one that's used to search a directory for files that match a given string. This is not a very useful plugin, but will let me demonstrate the basics of building a CLI in NodeJS.
Creating the Project
First things first: let's create a new project. Create a directory for the project, enter it and run
npm init to initialise the new project with a
package.json file. Answer the prompts if you wish, or just hit enter a bunch of times to get a template
package.json file that you can fill out at your own leisure.
package.json file is used by npm, Node's package manager, to know about your project, its dependencies and how it works. We need to make a couple of edits to it.
- remove the
mainentry: this is only used for modules that will be used through the module system (e.g.
var _ = require('underscore');).
preferGlobaland set it to true, which means if someone installs this module through npm and doesn't use the
--globaloption, they will be warned that the module is designed to be installed globally.
- add the
binobject, which maps commands to files. This means when this module is installed, npm will set up the
filesearchexecutable to execute
"description": "searches for files",
"test": "echo \"Error: no test specified\" && exit 1"
Creating the Script
index.js and add this to the top:
#! /usr/bin/env node
console.log('This is the filesearch script.');
Installing the Script
Now in your project you can run
npm link to install the script on your system. This creates a symlink to your project so that you can run the project whilst working on it, with no need to keep reinstalling it over and over again.
npm link has run, you should be able to run
filesearch on the command line and see the string printed back:
~/git/filesearch > filesearch This is the filesearch script.
filesearch is going to be called with one argument, which is going to be the pattern to search through files for. We need to get at that argument. When a Node.js script is executed on the command line, the
process.argv array contains all the arguments used to call that script.
index.js so it instead logs out this array:
And now run the script again, this time with an argument:
~/git/filesearch > filesearch foo [ 'node', '/Users/jackfranklin/.nvm/v0.10.32/bin/filesearch', 'foo']
The first argument is always
node, and the second is the path to the file that has been executed. Any following arguments are ones that the user has called your script with, and those are the ones we care about. We can use
slice to get an array of just the arguments we need:
var userArgs = process.argv.slice(2);
var searchPattern = userArgs;
Now we have the one argument we need.
Searching for Files
We'll hand the actual searching of the files over to a combination of two Unix commands,
grep. We can use
ls -a to list all files in the current directory, and pass them to
grep to search for our actual pattern.
To run a command in the system we can use the
exec method of the
child_process module - a module that comes with Node and doesn't need to be separately installed - to execute the right command, passing in the search pattern the user passed in through to
var exec = require('child_process').exec;
var child = exec('ls -a | grep ' + searchPattern, function(
And that is that! We can now run
filesearch and see the results:
~/git/filesearch > filesearch package package.json
If this was a real module that I was working on publishing there's a couple of things I'd do before hitting
- ensure a good, well written README
- decide on an initial version number (I tend to go for
0.1.0) and then follow semver
When your module is ready, simply run
npm publish to push it onto npm. If you've not registered on npm, you can run
npm adduser and follow the prompts to set up and authenticate yourself.
Once published, users can then install your module using
npm install --global filesearch.