node.js学习笔记

date: 2017.01.20; modification:2018.03.22

目录:

1 node.js作为linux命令行脚本(代替shell)

1.1 基本用法


    #!/usr/bin/env node

    console.log("hello world");

1.2 返回值


    if (err) {
      process.exit(1);
    } else {
      process.exit(0);
    }

1.3 等待用户输入


    var readlineSync = require("readline-sync");
    // 等待输入
    var userName = readlineSync.question("May I have your name? ");
    console.log("Hi " + userName + "!");

    // 阴文输入
    var favFood = readlineSync.question("What is your favorite food? ", { hideEchoBack: true });
    console.log("Oh, " + userName + " loves " + favFood + "!");

1.4 获取命令行参数(基本形式)


    console.log("hello ", process.argv[2]);

1.5 获取命令行参数(option形式: 如--help, -a)


    var argv = require("yargs").argv;
    console.log("hello ", argv.name);

运行: ./hello --name=mike
显示: hello mike

单个字母用于短选项:


    console.log("hello ", argv.n);

运行: ./hello -n mike
显示: hello mike

获取option之外(不带"--"或者"-"的)的命令行参数:

console.log(argv._);

更多选项配置:


    var argv = require("yargs")
        .option("n", { alias : "name", demand: true, default: "tom", describe: "your name", type: "string" })
        .argv;

无参选项:


    var argv = require("yargs").boolean(["n"]).argv;

帮助信息:


    var argv = require("yargs")
        .usage("Usage: hello [options]")
        .example("hello -n tom", "say hello to Tom")
        .help("h")
        .alias("h", "help")
        .epilog("copyright 2015")
        .argv;

子命令(类似与git commit):


    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);

1.6 文件操作

1.6.1 读取文本文件


    var text = fs.readFileSync(fileName, "utf8");
    text.split(/\r?\n/).forEach(function (line) {
        ...
    });

1.6.2 写入文本文件


    fs.writeFileSync(fileName, str, 'utf8');
    var out = fs.createWriteStream(fileName, { encoding: "utf8" });
    out.write(str);
    out.end();

1.6.3 判断文件是否存在


    ret = fs.existsSync(path); // 返回bool类型, true为存在.

1.6.4 获取文件信息


    ret = fs.statSync(path); // 返回 fs.Stats 的实例

stats类中的方法有:

方法 描述
stats.isFile() 如果是文件返回 true, 否则返回 false.
stats.isDirectory() 如果是目录返回 true, 否则返回 false.
stats.isBlockDevice() 如果是块设备返回 true, 否则返回 false.
stats.isCharacterDevice() 如果是字符设备返回 true, 否则返回 false.
stats.isSymbolicLink() 如果是软链接返回 true, 否则返回 false.
stats.isFIFO() 如果是FIFO, 返回true, 否则返回 false. FIFO是UNIX中的一种特殊类型的命令管道.
stats.isSocket() 如果是 Socket 返回 true, 否则返回 false.

1.7 管道


    process.stdin.resume();
    process.stdin.setEncoding("utf8");
    process.stdin.on("data", function(data) {
        process.stdout.write(data);
    });

运行: echo "foo" | ./hello
显示: hello foo

1.7.1 shell命令间管道

var proc = require('procstreams');
proc('cat app.log').pipe('wc -l').data(function (stdout, stderr) {
    console.log(stdout);
});

1.7.2 重定向到文件


    cat('input.txt').to('output.txt');
    cat('input.txt').toEnd('output.txt');

1.8 Linux系统信号


    process.on("SIGINT", function () {
        console.log("User interrupted");
        process.exit(1);
    });

1.9 进度条


    // width: 显示宽度, total: 总数据量, tick: 每次的数据量. 当所有tick的值加起来等于total则为100%.
    var ProgressBar = require('progress');

    var cols = parseInt(sh.exec("echo $COLUMNS").stdout); // 获取终端列数
    var progressBar = new ProgressBar(':bar :percent ', { width: cols-5, total: 300, complete: "#" });
    var timer = setInterval(function () {
        progressBar.tick(10);
        if (progressBar.complete) {
            console.log('\ncomplete\n');
            clearInterval(timer);
        }
    }, 100);

2 调用命令行程序

2.1 通过shelljs

npm install shelljs

shelljs项目主页: https://github.com/shelljs/shelljs

调用命令:


    var sh = require("shelljs");
    sh.echo("hello");

调用命令的通用方法:


    ret = sh.exec("ls" + name, {silent:true}); // silent表示不直接显示命令行输出, echo除外.
    //结果分别在: ret.code, ret.stdout, ret.stderr中.

或者可以用global模式(目前已不建议, 因为会污染global环境):


    require("shelljs/global");
    echo("hello"); // global模式下可以直接写shell命令.

常用命令:


    var ret = sh.find("../test/").filter(function(file) { return file.match(/\.js$/); }); // 返回数组

    sh.sed("-i", "PROGRAM_VERSION", "v0.1.3", "source.js");
    sh.sed(/.*DELETE_THIS_LINE.*\n/, "", "source.js");
    sh.sed(/(\w+)\s(\w+)/, "$2, $1", "file.txt");

其他命令说明见: shelljs项目主页

模拟xargs:


    sh.ls("*.js").forEach(function(file) { sh.sed("-i", /.*REPLACE_LINE_WITH_MACRO.*\n/, sh.cat("macro.js"), file); });

2.2 通过子进程


    var spawn = require("child_process").spawn;
    free = spawn("free", ["-m"]); 

    // 捕获标准输出并将其打印到控制台 
    free.stdout.on("data", function (data) { 
        console.log("standard output:\n" + data); 
    }); 

    // 捕获标准错误输出并将其打印到控制台 
    free.stderr.on("data", function (data) { 
        console.log("standard error output:\n" + data); 
    }); 

    // 注册子进程关闭事件 
    free.on("exit", function (code, signal) { 
        console.log("child process eixt ,exit:" + code); 
    });

2.3 通过exec


    require("child_process").exec; 
    var cmdStr = "curl http://www.weather.com.cn/data/sk/101010100.html";
    exec(cmdStr, function(err,stdout,stderr){
        if(err) {
            console.log("get weather api error:"+stderr);
        } else {
            /*
            这个stdout的内容就是上面我curl出来的这个东西:
            {"weatherinfo":{"city":"北京","cityid":"101010100","temp":"3",
            "WD":"西北风","WS":"3级","SD":"23%","WSE":"3","time":"21:20",
            "isRadar":"1","Radar":"JC_RADAR_AZ9010_JB","njd":"暂无实况","qy":"1019"}}
            */
            var data = JSON.parse(stdout);
            console.log(data);
        }
    });

2.4 调用shell脚本

调用传参数的shell脚本(child_process.execFile())


    var callfile = require("child_process").execFile;
    var username = "test";
    callfile("a.sh", ["-U", username], null, function (err, stdout, stderr) {
        ...
    });

2.5 同步调用子进程


    var execSync = require('child_process').execSync;

    try {
        var result = execSync("git log", { encoding: "utf8" });
        process.stdout.write(result);
    } catch(e) {
        console.log(e.status); // 命令返回值
        console.log(e.stderr); // err信息
    }

3 log系统

3.1 (console-log-level)可以控制打印级别的简单log模块:

与console.log类似, 只是添加了打印级别的控制. 适合简单的单一文件脚本的简单log需求.

npm install console-log-level

用法:

var logger = require('console-log-level')({ level: 'info' })
 
logger.debug('b') // will not do anything 
logger.info('c')  // will output 'c\n' on STDOUT 
logger.warn('d')  // will output 'd\n' on STDERR 
logger.error('e') // will output 'e\n' on STDERR 

4 参考

十大Node.js 的Web框架, 快速提升工作效率