Thực thi và nhận đầu ra của một lệnh shell trong node.js


113

Trong node.js, tôi muốn tìm cách lấy đầu ra của lệnh đầu cuối Unix. Có cách nào để làm điều này?

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

Đây là một bản sao hay nó mô tả một cái gì đó hoàn toàn khác? stackoverflow.com/questions/7183307/…
Anderson Green,

Điều này có thể khiến bạn quan tâm.
Benekastah

Câu trả lời:


142

Đó là cách tôi làm trong một dự án mà tôi đang làm việc bây giờ.

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

Ví dụ: Truy xuất người dùng 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", "") });
        });
    });
};

3
Có thể làm cho hàm này trả về đầu ra của lệnh không? (Đó là những gì tôi đã cố gắng làm.)
Anderson xanh

1
đó là những gì mã đó làm. hãy nhìn vào ví dụ nội dung chỉnh sửa Tôi vừa làm
Renato Gama

2
@AndersonGreen Bạn sẽ không muốn hàm trở lại bình thường với bàn phím "return", vì nó đang chạy lệnh shell không đồng bộ. Do đó, tốt hơn là chuyển một lệnh gọi lại với mã sẽ chạy khi lệnh shell hoàn tất.
Nick McCurdy,

1
Rất tiếc, mẫu đầu tiên của bạn bỏ qua khả năng xảy ra lỗi khi nó gọi lệnh gọi lại đó. Tôi tự hỏi điều gì sẽ xảy ra stdoutnếu có lỗi. Hy vọng là xác định và tài liệu.
doug65536

31

Bạn đang tìm kiếm 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);
      }
   });

Như đã chỉ ra bởi Renato, hiện nay cũng có một số gói thực thi đồng bộ , hãy xem đồng bộ hóa- thực thi có thể là những gì bạn đang tìm kiếm. Tuy nhiên, hãy lưu ý rằng node.js được thiết kế để trở thành một máy chủ mạng hiệu suất cao một luồng, vì vậy nếu đó là thứ bạn đang muốn sử dụng nó, hãy tránh xa những thứ đồng bộ hóa-thực thi trừ khi bạn chỉ sử dụng nó trong khi khởi động hoặc một cái gì đó.


1
Trong trường hợp này, làm cách nào để lấy đầu ra của lệnh? Có phải "stdout" có chứa đầu ra dòng lệnh không?
Anderson Green,

Ngoài ra, có thể làm điều gì đó tương tự mà không sử dụng lệnh gọi lại không?
Anderson Green,

Đúng, stdout chứa đầu ra của chương trình. Và không, không thể làm điều đó nếu không có lệnh gọi lại. Mọi thứ trong node.js được định hướng là không chặn, có nghĩa là mỗi khi bạn thực hiện IO, bạn sẽ sử dụng lệnh gọi lại.
hexist

Lưu ý rằng nếu bạn đang tìm kiếm sử dụng javascript để làm scripty kinda điều mà bạn thực sự muốn chờ trên đầu ra và đó đại loại như vậy, bạn có thể nhìn vào v8 vỏ, D8
hexist

@hexist có một số Syncphương pháp tự nhiên có sẵn, ngay cả như vậy IMHO nó nên tránh
Renato Gama

29

Nếu bạn đang sử dụng nút muộn hơn 7.6 và bạn không thích kiểu gọi lại, bạn cũng có thể sử dụng promisifychức năng của node-use với async / awaitđể nhận các lệnh shell đọc rõ ràng. Dưới đây là một ví dụ về câu trả lời được chấp nhận, sử dụng kỹ thuật này:

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

module.exports.getGitUser = async function getGitUser () {
  const name = await exec('git config --global user.name')
  const email = await exec('git config --global user.email')
  return { name, email }
};

Điều này cũng có thêm lợi ích là trả về một lời hứa bị từ chối trên các lệnh không thành công, có thể được xử lý bằng try / catchbên trong mã không đồng bộ.


Bạn đã thử cái này chưa? Tôi đang nhận được { stdout: string, stderr: string }kết quả choawait exec(...)
fwoelffel

1
Vâng, tôi nên làm rõ rằng điều này cung cấp cho bạn đầu ra shell đầy đủ , bao gồm cả stdout và stderr. Nếu bạn muốn chỉ là đầu ra, bạn có thể thay đổi dòng cuối cùng để: return { name: name.stdout.trim(), email: email.stdout.trim() }.
Ansikt

16

Nhờ câu trả lời của Renato, tôi đã tạo ra một ví dụ thực sự cơ bản:

const exec = require('child_process').exec

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

Nó sẽ chỉ in tên người dùng git toàn cầu của bạn :)


11

Yêu cầu

Điều này sẽ yêu cầu Node.js 7 trở lên có hỗ trợ Promises và Async / Await.

Giải pháp

Tạo một hàm wrapper dùng đòn bẩy để kiểm soát hành vi của child_process.execlệnh.

Giải trình

Sử dụng các hứa hẹn và một hàm không đồng bộ, bạn có thể bắt chước hành vi của một trình bao trả về đầu ra, mà không rơi vào địa ngục gọi lại và với một API khá gọn gàng. Sử dụng awaittừ khóa, bạn có thể tạo một tập lệnh dễ đọc, trong khi vẫn có thể hoàn thành công việc child_process.exec.

Mẫu mã

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

Sử dụng

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

Đầu ra mẫu

root:x:0:0::/root:/bin/bash
[output trimmed, bottom line it succeeded]

Error: Command failed: cat /etc/shadow
cat: /etc/shadow: Permission denied

Hãy thử nó trực tuyến.

Repl.it .

Nguồn lực bên ngoài

Những lời hứa .

child_process.exec.

Bảng hỗ trợ Node.js .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.