Node.js - child_process.exec和输出重定向

时间:2014-04-27 05:44:25

标签: javascript json node.js

我正在尝试使用Node.js编写文件模板脚本。我有一个名为template.json的JSON文件,它存储模板信息。我的脚本背后的想法是,如果我输入类似:

tmpl.js java Joe

它将执行以下操作:

  1. 致电touch Joe.java
  2. 阅读template.json以获取Java文件的模板
  3. 使用其信息将所有占位符替换为Joe
  4. 将结果写入Joe.java
  5. 执行emacsclient Joe.java
  6. 现在,我按如下方式编写了这个脚本:

    #!/usr/local/bin/node --harmony
    
    var templates = require('./config/template.json'),
        args = process.argv;
    
    if (args.length < 4) {
        console.log("Not enough arguments!");
    } 
    else {
        var type = args[2],
            name = args[3];
        if (type in templates) {
            var tmpl = templates[type],
                contents = make_output(tmpl["format"],name),
                file_name = name + tmpl["extension"],
                command = "touch " + file_name + " && echo -e '" + contents +
                "' &> " + file_name + " && emacsclient " + file_name;
            invoke(command);
        }
        else {
            console.log("No template for %s", type);
        }
    }
    
    
    //Helpers
    
    //Invokes comm with args in the terminal, returns all output
    //Does not play nice with command redirection
    function invoke(comm) {
        var exec = require('child_process').exec,
        child = exec(comm,
                 function (error, stdout, stderr) {
                             if (error !== null) {
                     console.log(stderr);
                     }
                 });
    }
    
    //If template is a format string, processes it with x as the
    //replacement. Otherwise, just evaluates.
    //Limited to one replacement at most.
    function make_output(template, x) {
        if(/.*\%s.*/i.test(template)) {
            var util = require('util');
            return util.format(template,x);
        }
        else {
            return template;
        }
    }
    

    基本上,它最终构建的命令类似于:

    touch Joe.java && echo -e `bunch of template stuffs` &> Joe.java && emacsclient Joe.java
    

    现在,我得到的问题是上面的命令依赖于输出重定向,我的invoke命令没有很好地处理 - 具体来说,一切都在执行,但我得到一个空文件!有没有办法可以更改invoke或我正在构建的调用以避免此问题?

1 个答案:

答案 0 :(得分:2)

问题是,节点child_process.exec启动sh,但您使用的是bash特有的功能。 &>& >中被解释为sh(两个运算符:一个控制运算符和一个重定向运算符),echo -e将使用sh的内置实现echo,不理解-e

可能可以解决上述问题,但像你一样使用shell是脆弱的。例如,如果您的模板包含单引号('),则这些引号可能会干扰您在命令中使用的单引号。一种更健壮的方法是将代码的主要部分更改为使用fs.writeFileSync而不是使用shell命令写入文件:

var templates = require('./config/template.json'),
    fs = require("fs"),
    args = process.argv;

if (args.length < 4) {
    console.log("Not enough arguments!");
}
else {
    var type = args[2],
        name = args[3];
    if (type in templates) {
        var tmpl = templates[type],
            contents = make_output(tmpl["format"],name),
            file_name = name + tmpl["extension"],
            command = "emacsclient " + file_name;

        fs.writeFileSync(file_name, contents);

        invoke(command);
    }
    else {
        console.log("No template for %s", type);
    }
}

您还希望修改make_output以执行echo -e为您完成的转换。