Now, let's see how to run scripts with Node.js. It's quite simple; let's start by referring to the help message shown previously. The command-line pattern is just a script filename and some script arguments, which should be familiar to anyone who has written scripts in other languages.
For this and other examples in this book, it doesn't truly matter where you put the files. However, for the sake of neatness, you can start by making a directory named node-web-dev in the home directory of your computer, and inside that creating one directory per chapter (for example, chap02 and chap03).
First, create a text file named ls.js with the following content:
const fs = require('fs');
const util = require('util');
const fs_readdir = util.promisify(fs.readdir);
(async () => {
const files = await fs_readdir('.');
for (let fn of files) {
console.log(fn);
}
})().catch(err => { console.error(err); });
Next, run it by typing the following command:
$ node ls.js ls.js
This is a pale cheap imitation of the Unix ls command (as if you couldn't figure that out from the name). The readdir function is a close analog to the Unix readdir system call (type man 3 readdir in a Terminal window to learn more) and is used to list the files in a directory.
We have written this using an inline async function, the await keyword, and an ES2015 for..of loop. Using util.promisify, we can convert any callback-oriented function so it returns a Promise, so that the Promise plays well with the await keyword.
By default fs module functions use the callback paradigm, as does most Node.js modules. But within async functions it is more convenient if functions instead return promises. Using util.promisify we can make it so.
This script is hardcoded to list files in the current directory. The real ls command takes a directory name, so let's modify the script a little.
Command-line arguments land in a global array named process.argv. Therefore we can modify ls.js, copying it as ls2.js, as follows to see how this array works:
const fs = require('fs');
const util = require('util');
const fs_readdir = util.promisify(fs.readdir);
(async () => {
var dir = '.';
if (process.argv[2]) dir = process.argv[2];
const files = await fs_readdir(dir);
for (let fn of files) {
console.log(fn);
}
})().catch(err => { console.error(err); });
You can run it as follows:
$ pwd
/Users/David/chap02
$ node ls2 ..
chap01
chap02
$ node ls2
app.js
ls.js
ls2.js
We simply checked if a command-line argument was present, if (process.argv[2]). If it was, we overrode the value of the dir variable, dir = process.argv[2], and we then used that as the readdir argument.
If you give it a non-existent directory pathname, an error will be thrown and printed using the catch clause. That looks like so:
$ node ls2.js /nonexistent
{ Error: ENOENT: no such file or directory, scandir '/nonexistent'
errno: -2,
code: 'ENOENT',
syscall: 'scandir',
path: '/nonexistent' }