La facilidad de uso de un lenguaje de programación depende, en gran medida, de su capacidad para desarrollar programas de línea de comandos.
Dado que Node.js es una de las herramientas de desarrollo más populares en la actualidad, saber cómo usarlo para desarrollar programas de línea de comandos es una habilidad que los desarrolladores web deberían dominar.

Recientemente, el blog de Npm tiene una serie deartículos, que me parecen muy bien escritos. A continuación, este es el tutorial que he ampliado a partir de ellos, y debería ser la mejor solución disponible actualmente.
1. Scripts ejecutables
Empecemos desde lo más simple.
Primero, escribe un script ejecutable llamado hello usando el lenguaje JavaScript.
#!/usr/bin/env node
console.log('hello world');
Luego, modifica los permisos de hello.
$ chmod 755 hello
Ahora, hello ya se puede ejecutar.
$ ./hello hello world
Si quieres eliminar la ruta delante de hello, puedes añadir la ruta de hello a la variable de entorno PATH. Sin embargo, otra mejor manera es crear un nuevo package.json en el directorio actual y escribir el siguiente contenido.
{
"name": "hello",
"bin": {
"hello": "hello"
}
}
Luego ejecuta el comando npm link.
$ npm link
Ahora, al ejecutar hello de nuevo, no es necesario escribir la ruta.
$ hello hello world
2. Escritura original de los argumentos de línea de comandos
Los argumentos de línea de comandos se pueden obtener con la variable de sistema process.argv.
#!/usr/bin/env node
console.log('hello ', process.argv[2]);
Al ejecutar, solo tienes que añadir los argumentos directamente después del archivo de script.
$ ./hello tom hello tom
3. Crear nuevos procesos
El script puede crear subprocesos mediante el módulo child_process, permitiendo así ejecutar comandos del sistema Unix.
#!/usr/bin/env node
var name = process.argv[2];
var exec = require('child_process').exec;
var child = exec('echo hello ' + name, function(err, stdout, stderr) {
if (err) throw err;
console.log(stdout);
});
El uso es el siguiente.
$ ./hello tom hello tom
4. Módulo shelljs
shelljsEl módulo reenvuelve child_process, lo que facilita la invocación de comandos del sistema. Es necesario instalarlo antes de usarlo.
npm install --save shelljs
Luego, reescribe el script.
#!/usr/bin/env node
var name = process.argv[2];
var shell = require("shelljs");
shell.exec("echo hello " + name);
El código anterior es el modo local de shelljs, es decir, ejecuta comandos shell mediante el método exec. También existe un modo global que permite escribir comandos shell directamente en el script.
require('shelljs/global');
if (!which('git')) {
echo('Sorry, this script requires git');
exit(1);
}
mkdir('-p', 'out/Release');
cp('-R', 'stuff/*', 'out/Release');
cd('lib');
ls('*.js').forEach(function(file) {
sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
sed('-i', /.*REMOVE_THIS_LINE.*/n/, '', file);
sed('-i', /.*REPLACE_LINE_WITH_MACRO.*/n/, cat('macro.js'), file);
});
cd('..');
if (exec('git commit -am "Auto-commit"').code !== 0) {
echo('Error: Git commit failed');
exit(1);
}
5. Módulo yargs
shelljs solo resuelve cómo invocar comandos shell, mientras que el módulo yargs puede resolver cómo manejar los argumentos de línea de comandos. También requiere instalación.
$ npm install --save yargs
El módulo yargs proporciona el objeto argv para leer los argumentos de línea de comandos. Observa el hello reescrito.
#!/usr/bin/env node
var argv = require('yargs').argv;
console.log('hello ', argv.name);
Al usarlo, las dos formas siguientes son válidas.
$ hello --name=tom hello tom $ hello --name tom hello tom
Si cambias argv.name a argv.n, puedes usar la forma de parámetro corto de una sola letra.
$ hello -n tom hello tom
Se puede usar el método alias para especificar que name es un alias de n.
#!/usr/bin/env node
var argv = require('yargs')
.alias('n', 'name')
.argv;
console.log('hello ', argv.n);
De esta manera, tanto los parámetros cortos como los largos se pueden utilizar.
$ hello -n tom hello tom $ hello --name tom hello tom
El objeto argv tiene una propiedad de guion bajo (_), que permite obtener los argumentos que no comienzan con guion.
#!/usr/bin/env node
var argv = require('yargs').argv;
console.log('hello ', argv.n);
console.log(argv._);
El uso es el siguiente.
$ hello A -n tom B C hello tom [ 'A', 'B', 'C' ]
6. Configuración de los argumentos de línea de comandos
El módulo yargs también proporciona 3 métodos para configurar los argumentos de línea de comandos.
- demand: si es obligatorio
- default: valor por defecto
- describe: descripción
#!/usr/bin/env node
var argv = require('yargs')
.demand(['n'])
.default({n: 'tom'})
.describe({n: 'your name'})
.argv;
console.log('hello ', argv.n);
El código anterior especifica que el parámetro n es obligatorio, con valor por defecto tom, y muestra una línea de descripción.
El método options permite escribir toda esta configuración en un objeto.
#!/usr/bin/env node
var argv = require('yargs')
.option('n', {
alias : 'name',
demand: true,
default: 'tom',
describe: 'your name',
type: 'string'
})
.argv;
console.log('hello ', argv.n);
A veces, algunos parámetros no necesitan un valor y solo actúan como un interruptor; en este caso, se puede usar el método boolean para especificar que estos parámetros devuelvan un valor booleano.
#!/usr/bin/env node
var argv = require('yargs')
.boolean(['n'])
.argv;
console.log('hello ', argv.n);
En el código anterior, el parámetro n siempre devuelve un valor booleano; el uso es el siguiente.
$ hello hello false $ hello -n hello true $ hello -n tom hello true
El método boolean también se puede escribir como una propiedad dentro del objeto option.
#!/usr/bin/env node
var argv = require('yargs')
.option('n', {
boolean: true
})
.argv;
console.log('hello ', argv.n);
7. Información de ayuda
El módulo yargs proporciona los siguientes métodos para generar información de ayuda.
- usage: formato de uso
- example: proporciona ejemplos
- help: muestra información de ayuda
- epilog: aparece al final de la información de ayuda
#!/usr/bin/env node
var argv = require('yargs')
.option('f', {
alias : 'name',
demand: true,
default: 'tom',
describe: 'your name',
type: 'string'
})
.usage('Usage: hello [options]')
.example('hello -n tom', 'say hello to Tom')
.help('h')
.alias('h', 'help')
.epilog('copyright 2015')
.argv;
console.log('hello ', argv.n);
El resultado de la ejecución es el siguiente.
$ hello -h Usage: hello [options] Options: -f, --name your name [string] [required] [default: "tom"] -h, --help Show help [boolean] Examples: hello -n tom say hello to Tom copyright 2015
8. Subcomandos
El módulo yargs también permite configurar subcomandos al estilo Git mediante el método command.
#!/usr/bin/env node
var argv = require('yargs')
.command("morning", "good morning", function (yargs) {
console.log("Good Morning");
})
.command("evening", "good evening", function (yargs) {
console.log("Good Evening");
})
.argv;
console.log('hello ', argv.n);
El uso es el siguiente.
$ hello morning -n tom Good Morning hello tom
Se puede combinar esta funcionalidad con el módulo shellojs.
#!/usr/bin/env node
require('shelljs/global');
var argv = require('yargs')
.command("morning", "good morning", function (yargs) {
echo("Good Morning");
})
.command("evening", "good evening", function (yargs) {
echo("Good Evening");
})
.argv;
console.log('hello ', argv.n);
Cada subcomando suele tener sus propios parámetros; en este caso, es necesario especificarlos por separado en la función de devolución de llamada. Dentro de la función de devolución de llamada, primero se debe usar el método reset para restablecer el objeto yargs.
#!/usr/bin/env node
require('shelljs/global');
var argv = require('yargs')
.command("morning", "good morning", function (yargs) {
echo("Good Morning");
var argv = yargs.reset()
.option("m", {
alias: "message",
description: "provide any sentence"
})
.help("h")
.alias("h", "help")
.argv;
echo(argv.m);
})
.argv;
El uso es el siguiente.
$ hello morning -m "Are you hungry?" Good Morning Are you hungry?
9. Otros asuntos
(1) Valor de retorno
Según la tradición de Unix, un programa devuelve 0 si se ejecuta correctamente; de lo contrario, devuelve 1.
if (err) {
process.exit(1);
} else {
process.exit(0);
}
(2) Redirección
Unix permite redirigir datos entre programas mediante tuberías.
$ ps aux | grep 'node'
El script puede obtener los datos redirigidos escuchando el evento data de la entrada estándar.
process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data', function(data) {
process.stdout.write(data);
});
El uso es el siguiente:
$ echo 'foo' | ./hello hello foo
(3) Señales del sistema
El sistema operativo puede enviar señales a los procesos en ejecución; el objeto process puede escuchar los eventos de señal.
process.on('SIGINT', function () {
console.log('Got a SIGINT');
process.exit(0);
});
El método para enviar señales es el siguiente.
$ kill -s SIGINT [process_id]
Fuente original: http://www.ruanyifeng.com/blog/2015/05/command-line-with-node.html