Last updated at Fri, 03 Nov 2017 22:43:01 GMT
Setting Up
Running a Node Script
We are going to talk about creating shell scripts with node.js. The first thing that you need to do is install node.js. You can get the installers from https://nodejs.org/en/download/, or use your favorite package manager.
Let’s go straight in and write our first script.
The first thing to do is to create a file called script.js with the following code:
console.log('hello world')
We can now execute this script by running the following command in our shell:
node script.js
If you are on a Unix-like system, you might prefer to directly create an executable file in 2 steps:
- Tell the operating system what the interpreter for the code with Shebang. You can do that putting this “special” line at the top of your script which means that your script will now look like this:
#!/usr/bin/env node console.log('hello world')
- Give that file execution permissions:
chmod +x script.js
Now, you can execute that script directly by using:
./script.js
And, that’s it… Ok, ok, let me show you a few more interesting things with node!
Reading from files
Usually when you read from a file, you don’t want to block your execution thread. This means that you don’t need to load all the file in memory at the same time, especially for long files. The following is a simple example on how to do it:
#!/usr/bin/env node fs.readFile('/etc/passwd', function (err, data) { if (err) throw err; console.log(data); });
But there may be exceptions when you need to read the whole file! Maybe you need to load a configuration file before anything else happens or any other good reason you can think of. In this case, you can load files as follow:
#!/usr/bin/env node var fs = require('fs'); var contents = fs.readFileSync('my_file.txt', 'utf8'); console.log(contents);
Pipes
An interesting option when you are working in shell is the possibility to use pipes to chain the output of one command to the input of the next one. For example, the following will send the output of ps
to the input of grep
and keep only the lines containing “python”:
“ps | grep python”
In node.js, you can deal with the standard input of your script using process.stdin
. The following example will print the input to the console
#!/usr/bin/env node var readInput = function(callback){ var input = ''; process.stdin.setEncoding('utf8'); process.stdin.on('readable', function() { var chunk = process.stdin.read(); if (chunk !== null) { input += chunk; } }); process.stdin.on('end', function() { callback(input); }); } var initScript = function(input){ console.log(input) } readInput(initScript);
Now, using that script, we can print “hello world.” by using the following line:
echo 'hello world.' | ./index.js
Next, the natural step here is to start thinking about sending our output to another process using pipe. As we do so, we quickly realise that there is a risk of getting disgusting errors in our output (eg. after runtime issues). I won’t go into details but if you want to look a bit more into this, I’d recommend to have a look at EPIPE BOMB and this project for a possible solution.
Note: to see the type of error I described in the above paragraph, you can execute something like:
ls | ./index.js | this_command_doesnt_exist
Managing Dependencies
I’m going to assume you’re already familiar with npm. If not, this page is your friend.
First we need to create the package.json file. With this file, we will be able to use and share our scripts without adding all the Javascript code from the 3rd party modules we use. By sharing our code and that file, other users will be able to install all dependencies using npm install
. For example, let’s create a package.json file that looks like this:
//package.json { "name": "examplepackagejson", "version": "0.1.0", "description": "An example module to illustrate the usage of a package.json", "author": "Raul Martin", "dependencies": { "cheerio": "^0.19.0", "request": "^2.64.0" } }
To install these dependencies, run:
npm install
Now you can see a new folder called node_modules and in it the cheerio and request code. Additionally, the versions of these will be equal or higher than the ones we had put in our package.json file without going up a major version (thanks to the ^ characters).
Environment Variables and Script Arguments
To access environment variables in your script, you just need to use the process.env
property. For example, to get $HOME
, you can use process.env.HOME
(if you are thinking about using this to pass configuration variables to your script right now, I would think you should also have a look at the nconf project). You can use process.argv
to use arguments passed into your script. It is an array containing the full list of arguments.
#!/usr/bin/env node process.argv.forEach(function (param, position) { console.log(position + ': ' + param); });
You can test that code with:
node script_with_args.js param1 param2=value2
or
./script_with_args.js param1 param2=value2
And the result should be something like:
0: /usr/local/bin/node 1: /Users/myname/workspace/myproject/script_with_args.js 2: param1 3: param2=value2
If you need to manage your arguments nicely, you should use the Commander module. Here’s an interesting way to manage you package.json file when you identify the need for a new dependency (here, Commander). You just need to run the following command (in your project directory):
npm install commander save
This will have done two things:
- downloaded the Commander project
- updated you package.json file to include that dependency (with the correct version
Now, here’s an example on how to use Commander (call your file commander_example.js):
#!/usr/bin/env node var program = require('commander'); program .version('0.0.1') .option('p, peppers', 'Add peppers') .option('P, pineapple', 'Add pineapple') .option('b, bbqsauce', 'Add bbq sauce') .option('c, cheese [type]', 'Add the specified type of cheese [marble]', 'marble') .parse(process.argv); console.log('you ordered a pizza with:'); if (program.peppers) console.log(' peppers'); if (program.pineapple) console.log(' pineapple'); if (program.bbqSauce) console.log(' bbq'); //now i'm hungry console.log(' %s cheese', program.cheese);
You should start testing this code by running ./commander_example.js help
. So much fun! For more details, have a look at the npm Commander’s page. In a future blogpost, we will write an interesting script using most of the elements we described today. Keep an eye on this blog and you will be able to see how you can quickly put all those interesting concepts into practice.
See you later!
Ready to start getting insights from your applications? Sign up for a Logentries free trial today.