Updated: This article has been updated to not use eval

I was recently looking at writing my own command line utility using Node. While I found a few tutorials including a great one over at Javascript Playground I found many were out of date and some things took an extra bit of research to learn how to get started. To help others I decided to put this post together explaining how to make a simple command line calculator which simply takes two values and adds them together.

Pre-requisites

Before we get started there are a few pre-requisites that we need.

  • NodeJS installed (current version is 0.10.13)
  • NPM installed
  • Grunt-cli installed (if not run npm install -g grunt-cli)
  • Grunt-Init installed (if not run npm install -g grunt-init)
  • Node template for Grunt-Init (git clone [email protected]:gruntjs/grunt-init-node.git ~/.grunt-init/node)

Getting Going

Now we are ready we can started writing our command line tool using Node.

Create a directory for your new project, then use the Terminal to navigate to it, then you are able to initialise your project using

grunt-init node

This will then allow us to initialise our project, grunt-init will then ask us some questions regarding out project.

[?] Project name (calc) calc
[?] Description (The best project ever.) Simple command line calculator
[?] Version (0.1.0)
[?] Project git repository (git://github.com/jonathanfielding/calc.git) [email protected]:jonathan-fielding/CalcCLI.git
[?] Project homepage (https://github.com/jonathan-fielding/CalcCLI)
[?] Project issues tracker (https://github.com/jonathan-fielding/CalcCLI/issues)
[?] Licenses (MIT) 
[?] Author name (Jonathan Fielding) 
[?] Author email ([email protected]) 
[?] Author url (none) http://www.jonathanfielding.com
[?] What versions of node does it run on? (>= 0.8.0)
[?] Main module/entry point (lib/calc) 
[?] Npm test command (grunt nodeunit)
[?] Will this project be tested with Travis CI? (Y/n) n
[?] Do you need to make any changes to the above before continuing? (y/N) n

With our project initialised, we can take a quick look in our directory to see what grunt-init has generated.

Gruntfile.js
README.md
package.json
LICENSE-MIT
lib/calc.js
test/calc_test.js

If we load up the package.json in our editor is should look like this. As you can see

{
  "name": "calc",
  "description": "Simple command line calculator",
  "version": "0.1.0",
  "homepage": "https://github.com/jonathan-fielding/CalcCLI",
  "author": {
    "name": "Jonathan Fielding",
    "email": "[email protected]",
    "url": "http://www.jonathanfielding.com"
  },
  "repository": {
    "type": "git",
    "url": "[email protected]:jonathan-fielding/CalcCLI.git"
  },
  "bugs": {
    "url": "https://github.com/jonathan-fielding/CalcCLI/issues"
  },
  "licenses": [
    {
      "type": "MIT",
      "url": "https://github.com/jonathan-fielding/CalcCLI/blob/master/LICENSE-MIT"
    }
  ],
  "main": "lib/calc",
  "engines": {
    "node": ">= 0.8.0"
  },
  "scripts": {
    "test": "grunt nodeunit"
  },
  "devDependencies": {
    "grunt-contrib-jshint": "~0.6.0",
    "grunt-contrib-nodeunit": "~0.2.0",
    "grunt-contrib-watch": "~0.4.0",
    "grunt": "~0.4.1"
  },
  "keywords": []
}

We need to tell our package that it should be installed globally if possible, this can be achieved through adding the preferGlobal property. We also want to define that command that we will use on the command line, we can do this by adding a bin object. This object needs to list any commands the user may want to enter, for this example we will add one command calc. We will need to point this to our main js file used for the utility which is lib/calc.js.

"preferGlobal": "true",
"bin": {
    "calc" : "lib/calc.js"
}

We have told our package.json that whenever the user of our utility hits calc, it should run lib/calc.js however what we havent yet done is tell our script how it should be executed. We do this by opening up lib/calc.js and adding this line at the top.

#! /usr/bin/env node

This tells the script it needs to be executed using Node.

At the moment if we type calc into our Terminal, we will receive the error.

-bash: calc: command not found

This is because we have not installed our package yet so we are unable to test it. To install our package locally we simply need to run npm link which will give us access to the calc command in Terminal. You will probably notice that when you run this command npm will download some files, this is npm downloading all the dependancies required by your tool.

At the moment when we test our command calc nothing will happen, this is as expected.

When looking in the main plugin file (in this case lib/calc.js) we will see that grunt-init has generated this code.

exports.awesome = function() {
  return 'awesome';
};

exports is how in node we export methods and variables from your script, these can then be used in other scripts. In the case of our script this isn’t needed as it is unlikely our simple calculator will be used as part of other scripts so we can delete this.

We expect the users of our tool to enter the name of our tool then for the first argument they would pass the calculation they want to perform, it would look something like this.

calc 10 10

To achieve this we need to get the to first get the arguments, the parameters passed are stored in an array process.argv. We can output the contents of this array by adding.

console.log(process.argv);

And then run calc 10 10 in your terminal we should get this result

[ 'node', '/usr/local/bin/calc', '10' , '10' ]

The first two items in the array relate to how the script is executed and where the executable is, so third item is the first user defined argument. To get only the user supplied arguments we can simply slice the array at index 2.

var userArgs = process.argv.slice(2);

With our userArgs stored we can simply reference the arguments we pass as userArgs[0] and userArgs[1] however to make this easier to read we can simply store these in variables, because the original array stored these as strings we will need to use parseInt to convert them to an integer.

var value1 = parseInt(userArgs[0]);
var value2 = parseInt(userArgs[1]);

We now need to calculate the result of the argument passed by the user.For this example we will simply add the two values together.``Updated: This article has been updated to not use eval

I was recently looking at writing my own command line utility using Node. While I found a few tutorials including a great one over at Javascript Playground I found many were out of date and some things took an extra bit of research to learn how to get started. To help others I decided to put this post together explaining how to make a simple command line calculator which simply takes two values and adds them together.

Pre-requisites

Before we get started there are a few pre-requisites that we need.

  • NodeJS installed (current version is 0.10.13)
  • NPM installed
  • Grunt-cli installed (if not run npm install -g grunt-cli)
  • Grunt-Init installed (if not run npm install -g grunt-init)
  • Node template for Grunt-Init (git clone [email protected]:gruntjs/grunt-init-node.git ~/.grunt-init/node)

Getting Going

Now we are ready we can started writing our command line tool using Node.

Create a directory for your new project, then use the Terminal to navigate to it, then you are able to initialise your project using

grunt-init node

This will then allow us to initialise our project, grunt-init will then ask us some questions regarding out project.

[?] Project name (calc) calc
[?] Description (The best project ever.) Simple command line calculator
[?] Version (0.1.0)
[?] Project git repository (git://github.com/jonathanfielding/calc.git) [email protected]:jonathan-fielding/CalcCLI.git
[?] Project homepage (https://github.com/jonathan-fielding/CalcCLI)
[?] Project issues tracker (https://github.com/jonathan-fielding/CalcCLI/issues)
[?] Licenses (MIT) 
[?] Author name (Jonathan Fielding) 
[?] Author email ([email protected]) 
[?] Author url (none) http://www.jonathanfielding.com
[?] What versions of node does it run on? (>= 0.8.0)
[?] Main module/entry point (lib/calc) 
[?] Npm test command (grunt nodeunit)
[?] Will this project be tested with Travis CI? (Y/n) n
[?] Do you need to make any changes to the above before continuing? (y/N) n

With our project initialised, we can take a quick look in our directory to see what grunt-init has generated.

Gruntfile.js
README.md
package.json
LICENSE-MIT
lib/calc.js
test/calc_test.js

If we load up the package.json in our editor is should look like this. As you can see

{
  "name": "calc",
  "description": "Simple command line calculator",
  "version": "0.1.0",
  "homepage": "https://github.com/jonathan-fielding/CalcCLI",
  "author": {
    "name": "Jonathan Fielding",
    "email": "[email protected]",
    "url": "http://www.jonathanfielding.com"
  },
  "repository": {
    "type": "git",
    "url": "[email protected]:jonathan-fielding/CalcCLI.git"
  },
  "bugs": {
    "url": "https://github.com/jonathan-fielding/CalcCLI/issues"
  },
  "licenses": [
    {
      "type": "MIT",
      "url": "https://github.com/jonathan-fielding/CalcCLI/blob/master/LICENSE-MIT"
    }
  ],
  "main": "lib/calc",
  "engines": {
    "node": ">= 0.8.0"
  },
  "scripts": {
    "test": "grunt nodeunit"
  },
  "devDependencies": {
    "grunt-contrib-jshint": "~0.6.0",
    "grunt-contrib-nodeunit": "~0.2.0",
    "grunt-contrib-watch": "~0.4.0",
    "grunt": "~0.4.1"
  },
  "keywords": []
}

We need to tell our package that it should be installed globally if possible, this can be achieved through adding the preferGlobal property. We also want to define that command that we will use on the command line, we can do this by adding a bin object. This object needs to list any commands the user may want to enter, for this example we will add one command calc. We will need to point this to our main js file used for the utility which is lib/calc.js.

"preferGlobal": "true",
"bin": {
    "calc" : "lib/calc.js"
}

We have told our package.json that whenever the user of our utility hits calc, it should run lib/calc.js however what we havent yet done is tell our script how it should be executed. We do this by opening up lib/calc.js and adding this line at the top.

#! /usr/bin/env node

This tells the script it needs to be executed using Node.

At the moment if we type calc into our Terminal, we will receive the error.

-bash: calc: command not found

This is because we have not installed our package yet so we are unable to test it. To install our package locally we simply need to run npm link which will give us access to the calc command in Terminal. You will probably notice that when you run this command npm will download some files, this is npm downloading all the dependancies required by your tool.

At the moment when we test our command calc nothing will happen, this is as expected.

When looking in the main plugin file (in this case lib/calc.js) we will see that grunt-init has generated this code.

exports.awesome = function() {
  return 'awesome';
};

exports is how in node we export methods and variables from your script, these can then be used in other scripts. In the case of our script this isn’t needed as it is unlikely our simple calculator will be used as part of other scripts so we can delete this.

We expect the users of our tool to enter the name of our tool then for the first argument they would pass the calculation they want to perform, it would look something like this.

calc 10 10

To achieve this we need to get the to first get the arguments, the parameters passed are stored in an array process.argv. We can output the contents of this array by adding.

console.log(process.argv);

And then run calc 10 10 in your terminal we should get this result

[ 'node', '/usr/local/bin/calc', '10' , '10' ]

The first two items in the array relate to how the script is executed and where the executable is, so third item is the first user defined argument. To get only the user supplied arguments we can simply slice the array at index 2.

var userArgs = process.argv.slice(2);

With our userArgs stored we can simply reference the arguments we pass as userArgs[0] and userArgs[1] however to make this easier to read we can simply store these in variables, because the original array stored these as strings we will need to use parseInt to convert them to an integer.

var value1 = parseInt(userArgs[0]);
var value2 = parseInt(userArgs[1]);

We now need to calculate the result of the argument passed by the user.For this example we will simply add the two values together.``

var answer = value1 + value2;

Finally we need to output this answer to the user, for this we will simply use console.log to output the answer.

console.log(answer);

Now if we go back to our Terminal and run the command

calc 10 10

The utility will reply with the answer

20

At this point we have a simple calculator for the command line which allows us to add 2 values together. While its unlikely you will use this utility on a day to day basis it has allowed us to learn about how to write a command line utility using Node.

What’s Next

We already have a working command line utility now we want to publish the utlity as a npm module, to do this we need to first authenticate yourself or signup with npm. To do this we run.

npm adduser

This will ask us to supply a username, password and email address. Once we are authenticated we need to ensure our project is a Git repository. We should also check the following:

  • We have added node_modules/ to our .gitignore, (grunt-init should have included a .gitignore file as part of the original template to make this easy for us)
  • We also need to ensure that our repository has a valid package.json (running npm link will verify this).
  • Push your repository to GitHub (or elsewhere, BitBucket offers a good alternative) and make sure your package.json has a repository object that looks like this
    "repository": {
       "type": "git",
       "url": "git://github.com/jonathanfielding/calc.git"
     }

Once you have checked you are happy with everything, simply run npm publish. This will publish your module and users can install through npm install modulename (As ‘calc’ is already taken on npm I haven’t published the utility created for this tutorial).

Credits

Thanks to Jack Franklin for his original post,  I based this article on what I learnt from his original post on creating a command line tool using Node.

Are you looking for your next role?

I work as an Engineering Manager at Beamly where we are currently looking for both Frontend and Full Stack software engineers based in our London office.

Find out more