【问题标题】:Execute and get the output of a shell command in node.js在 node.js 中执行并获取 shell 命令的输出
【发布时间】:2012-10-08 02:38:51
【问题描述】:

在 node.js 中,我想找到一种方法来获取 Unix 终端命令的输出。有没有办法做到这一点?

function getCommandOutput(commandString){
    // now how can I implement this function?
    // getCommandOutput("ls") should print the terminal output of the shell command "ls"
}

【问题讨论】:

标签: node.js shell command-line-interface


【解决方案1】:

如果您使用的是高于 7.6 的 node 并且您不喜欢回调样式,您还可以使用 node-util 的 promisify 函数和 async / await 来获得清晰读取的 shell 命令。以下是使用此技术的已接受答案的示例:

const { promisify } = require('util');
const exec = promisify(require('child_process').exec)

module.exports.getGitUser = async function getGitUser () {
  // Exec output contains both stderr and stdout outputs
  const nameOutput = await exec('git config --global user.name')
  const emailOutput = await exec('git config --global user.email')

  return { 
    name: nameOutput.stdout.trim(), 
    email: emailOutput.stdout.trim()
  }
};

这还有一个额外的好处,即在失败的命令上返回一个被拒绝的承诺,可以在异步代码中使用try / catch 处理。

【讨论】:

  • 你试过了吗?我得到{ stdout: string, stderr: string } 作为await exec(...) 的结果
  • 是的,我应该澄清一下,这会为您提供 full shell 输出,包括 stdout 和 stderr。如果只需要输出,可以将最后一行更改为:return { name: name.stdout.trim(), email: email.stdout.trim() }
【解决方案2】:

您可以使用ShellJS 包。
ShellJS 是基于 Node.js API 的 Unix shell 命令的可移植 (Windows/Linux/OS X) 实现。
见:https://www.npmjs.com/package/shelljs#execcommand--options--callback

import * as shell from "shelljs";

//usage:
//exec(command [, options] [, callback])

//example:
const version = shell.exec("node --version", {async: false}).stdout;
console.log("nodejs version", version);

【讨论】:

    【解决方案3】:

    您可以使用 nodejs 附带的 util 库从 exec 命令中获取承诺,并可以根据需要使用该输出。使用重组将 stdout 和 stderr 存储在变量中。

    const util = require('util');
    const exec = util.promisify(require('child_process').exec);
    
    async function lsExample() {
      const {
        stdout,
        stderr
      } = await exec('ls');
      console.log('stdout:', stdout);
      console.error('stderr:', stderr);
    }
    lsExample();

    【讨论】:

    • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
    【解决方案4】:

    这是我目前正在从事的项目中使用的方法。

    var exec = require('child_process').exec;
    function execute(command, callback){
        exec(command, function(error, stdout, stderr){ callback(stdout); });
    };
    

    获取 git 用户示例:

    module.exports.getGitUser = function(callback){
        execute("git config --global user.name", function(name){
            execute("git config --global user.email", function(email){
                callback({ name: name.replace("\n", ""), email: email.replace("\n", "") });
            });
        });
    };
    

    【讨论】:

    • 是否可以让这个函数返回命令的输出? (这就是我想要做的。)
    • 这就是代码的作用。看看我刚刚进行的编辑中的示例
    • @AndersonGreen 您不希望函数使用“return”键盘正常返回,因为它正在异步运行 shell 命令。因此,最好传入一个回调,其中包含在 shell 命令完成时应该运行的代码。
    • 哎呀,您的第一个示例在调用该回调时忽略了错误的可能性。我想知道如果出现错误,stdout 会发生什么。希望具有确定性和记录性。
    • execute 包装器的意义何在?
    【解决方案5】:

    要求

    这需要 Node.js 7 或更高版本并支持 Promises 和 Async/Await。

    解决方案

    创建一个包装函数,利用承诺控制child_process.exec 命令的行为。

    说明

    使用 Promise 和异步函数,您可以模仿 shell 返回输出的行为,而不会陷入回调地狱,而且 API 非常简洁。使用await 关键字,您可以创建一个易于阅读的脚本,同时仍然能够完成child_process.exec 的工作。

    代码示例

    const childProcess = require("child_process");
    
    /**
     * @param {string} command A shell command to execute
     * @return {Promise<string>} A promise that resolve to the output of the shell command, or an error
     * @example const output = await execute("ls -alh");
     */
    function execute(command) {
      /**
       * @param {Function} resolve A function that resolves the promise
       * @param {Function} reject A function that fails the promise
       * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
       */
      return new Promise(function(resolve, reject) {
        /**
         * @param {Error} error An error triggered during the execution of the childProcess.exec command
         * @param {string|Buffer} standardOutput The result of the shell command execution
         * @param {string|Buffer} standardError The error resulting of the shell command execution
         * @see https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
         */
        childProcess.exec(command, function(error, standardOutput, standardError) {
          if (error) {
            reject();
    
            return;
          }
    
          if (standardError) {
            reject(standardError);
    
            return;
          }
    
          resolve(standardOutput);
        });
      });
    }
    

    用法

    async function main() {
      try {
        const passwdContent = await execute("cat /etc/passwd");
    
        console.log(passwdContent);
      } catch (error) {
        console.error(error.toString());
      }
    
      try {
        const shadowContent = await execute("cat /etc/shadow");
    
        console.log(shadowContent);
      } catch (error) {
        console.error(error.toString());
      }
    }
    
    main();
    

    样本输出

    root:x:0:0::/root:/bin/bash
    [output trimmed, bottom line it succeeded]
    
    Error: Command failed: cat /etc/shadow
    cat: /etc/shadow: Permission denied
    

    在线试用。

    Repl.it.

    外部资源

    Promises.

    child_process.exec.

    Node.js support table.

    【讨论】:

    • 这是我认为最干净的选项,让人想起github.com/shelljs/shelljs(但更简单)。
    • 登录只是为了点赞。很好的答案。
    【解决方案6】:

    感谢雷纳托的回答,我创建了一个非常基本的示例:

    const exec = require('child_process').exec
    
    exec('git config --global user.name', (err, stdout, stderr) => console.log(stdout))
    

    它只会打印你的全局 git 用户名:)

    【讨论】:

      【解决方案7】:

      您正在寻找child_process

      var exec = require('child_process').exec;
      var child;
      
      child = exec(command,
         function (error, stdout, stderr) {
            console.log('stdout: ' + stdout);
            console.log('stderr: ' + stderr);
            if (error !== null) {
                console.log('exec error: ' + error);
            }
         });
      

      正如 Renato 所指出的,现在也有一些同步 exec 包,请参阅sync-exec,这可能是您正在寻找的更多内容。但请记住,node.js 被设计为单线程高性能网络服务器,因此,如果您要使用它,请远离 sync-exec 之类的东西,除非您仅在启动期间使用它什么的。

      【讨论】:

      • 这种情况下,如何获取命令的输出呢?是包含命令行输出的“stdout”吗?
      • 另外,是否可以在不使用回调的情况下做类似的事情?
      • 正确,stdout 包含程序的输出。不,没有回调就不可能做到这一点。 node.js 中的所有内容都以非阻塞为导向,这意味着每次执行 IO 时都会使用回调。
      • 请注意,如果您正在寻找使用 javascript 来执行脚本式的事情,而您真的想等待输出之类的事情,您可能会查看 v8 shell,d8
      • @hexist 有一些 Sync 方法本机可用,即使如此恕我直言,应该避免
      猜你喜欢
      • 2014-06-29
      • 2013-01-05
      • 2020-03-25
      • 2013-01-01
      • 2016-10-10
      • 2019-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多