Command-line Picker

Node.js brings JavaScript to systems programming. Systems programmers tend to write utilities that accept command-line arguments. Here is a Node.js script that prints its command-line arguments:

console.log(process.argv);

Put this code in a file named picker.js and run it in your terminal with the command node picker.js. You see that argument 0 is the path to the Node.js interpreter and that argument 1 is the name of the script.

Suppose you want to make a utility that randomly picks one of the command-line arguments. The first two parameters should not be included in the choices, so you use JavaScript's Array.slice method to get a subarray that excludes them:

const options = process.argv.slice(2);
console.log(options);

To pick one argument at random, you use Math.random to get a value in [0, 1), apply it to the length of the array, and round down to get a legal index:

const options = process.argv.slice(2);
const i = Math.floor(Math.random() * options.length);
console.log(options[i]);

Try running this script with some command-line arguments. Is each of the options eventually picked? Try running this script without any command-line arguments. What happens?

Getting command-line arguments right is hard. In many development environments, you get clues about what parameters are expected. You decide to similarly give the user some feedback about how the script should be invoked:

const options = process.argv.slice(2);
if (options.length === 0) {
console.error(`Usage: node ${process.argv[1]} option1 [option2 ...]`);
process.exit(1);
} else {
const i = Math.floor(Math.random() * options.length);
console.log(options[i]);
}

Try running this and providing no arguments. You find that the path of the script in the error message has too much detail. The path is an absolute path, and you just want to display the script's basename, which is the name of the file without any information about the directories it's in. You could strip off the leading directories from the string using a regular expression or string manipulation. However, unlike the browser, Node.js is designed with file manipulation in mind. It provides facilities for manipulating paths. You bring in the builtin path library and use its basename function:

const path = require('path');

const options = process.argv.slice(2);
if (options.length === 0) {
console.error(`Usage: node ${path.basename(process.argv[1])} option1 [option2 ...]`);
process.exit(1);
} else {
const i = Math.floor(Math.random() * options.length);
console.log(options[i]);
}

Try running this code in your browser's JavaScript console. Does it still pick an argument at random? Does it provide a helpful error message when no arguments are passed?