Exec: hiển thị stdout trên mạng


187

Tôi có kịch bản đơn giản này:

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

exec('coffee -cw my_file.coffee', function(error, stdout, stderr) {
    console.log(stdout);
});

trong đó tôi chỉ cần thực thi một lệnh để biên dịch tệp cà phê. Nhưng thiết bị xuất chuẩn không bao giờ được hiển thị trong bảng điều khiển, vì lệnh không bao giờ kết thúc (vì tùy chọn -w của cà phê). Nếu tôi thực thi lệnh trực tiếp từ bàn điều khiển, tôi nhận được thông báo như sau:

18:05:59 - compiled my_file.coffee

Câu hỏi của tôi là: có thể hiển thị các thông báo này với tệp thực thi node.js không? Nếu có thì thế nào? !

Cảm ơn


1
Tôi đến đây để tìm bắt stdout từ Python thực thi. Lưu ý rằng tất cả các cách bên dưới sẽ hoạt động, nhưng bạn cần chạy python với tùy chọn "-u", để thoát ra ngoài không có bộ đệm và do đó có cập nhật trực tiếp.
Andy

Câu trả lời:


264

Đừng sử dụng exec. Sử dụng spawnđó là một EventEmmiterđối tượng. Sau đó, bạn có thể nghe stdout/ stderrsự kiện ( spawn.stdout.on('data',callback..)) khi chúng xảy ra .

Từ tài liệu của NodeJS:

var spawn = require('child_process').spawn,
    ls    = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', function (data) {
  console.log('stdout: ' + data.toString());
});

ls.stderr.on('data', function (data) {
  console.log('stderr: ' + data.toString());
});

ls.on('exit', function (code) {
  console.log('child process exited with code ' + code.toString());
});

exec đệm đầu ra và thường trả về khi lệnh đã thực hiện xong.


22
Rất đẹp. FYI: Stdout / stderr event callback 'data' là một bộ đệm, vì vậy hãy gọi nó bằng .toString ()
SergeL

4
Đối với những người bạn không thể sinh sản để làm việc trên Windows, hãy xem câu trả lời tuyệt vời này .
tomekwi

17
exec cũng là một EventEuctor ít nhất là mới nhất.
Nikolay Tsenkov

4
Ngoài ra, hãy nhớ rằng cuộc gọi lại sẽ không được gọi, bất cứ khi nào chương trình xuất ra một dòng mới. Nếu bạn muốn nhận "sự kiện" từ quy trình con, quy trình này phải xóa bộ đệm ( flush(stdout);bằng C) để kích hoạt các sự kiện trong Node.js.
Julian F. Weinert

5
+1 trên exec cũng là một EventEuctor .. đã dành 2 giờ để cấu trúc lại chuỗi của tôi thành một mảng args (dòng lệnh ffmpeg rất dài và phức tạp) .. chỉ để tìm ra tôi không thực sự cần.
deadconversations

175

exec cũng sẽ trả về một đối tượng ChildProcess là EventEuctor.

var exec = require('child_process').exec;
var coffeeProcess = exec('coffee -cw my_file.coffee');

coffeeProcess.stdout.on('data', function(data) {
    console.log(data); 
});

HOẶC pipethiết bị xuất chuẩn của tiến trình con đến thiết bị xuất chuẩn chính.

coffeeProcess.stdout.pipe(process.stdout);

HOẶC kế thừa stdio bằng cách sử dụng sinh sản

spawn('coffee -cw my_file.coffee', { stdio: 'inherit' });

35
Có vẻ như điều này có thể được đơn giản hóa bằng cách sử dụng pipe:coffeeProcess.stdout.pipe(process.stdout);
Eric Freese

3
Nhận xét của @ EricFreese là những gì tôi đang tìm kiếm, vì tôi muốn tận dụng tính năng thay thế nhân vật của thiết bị xuất chuẩn (khai thác thước đo góc trong tập lệnh nút)
LoremIpsum

19
Đơn giản hơn : spawn(cmd, argv, { stdio: 'inherit' }). Xem nodejs.org/api/child_ process.html#child_ process_options_stdio để biết các ví dụ khác nhau.
Morgan Todarey Quilling

3
+1 cho đề xuất của @ MorganTodareyQuilling để sử dụng spawnvới stdio: 'inherit'. Nó tạo ra đầu ra chính xác hơn execvà đường ống stdout/ stderr, ví dụ như khi hiển thị thông tin tiến trình từ a git clone.
Livven

55

Đã có một số câu trả lời tuy nhiên không ai trong số họ đề cập đến cách tốt nhất (và dễ nhất) để làm điều này, đó là sử dụng spawn{ stdio: 'inherit' }tùy chọn . Nó dường như tạo ra đầu ra chính xác nhất, ví dụ như khi hiển thị thông tin tiến trình từ a git clone.

Đơn giản chỉ cần làm điều này:

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

spawn('coffee', ['-cw', 'my_file.coffee'], { stdio: 'inherit' });

Tín dụng cho @MorganTodareyQuilling vì đã chỉ ra điều này trong bình luận này .


1
Tôi thấy rằng khi quy trình con sử dụng đầu ra được định dạng như văn bản màu, sẽ stdio: "inherit"giữ nguyên định dạng đó trong khi child.stdout.pipe(process.stdout)không.
Rikki Gibson

Điều này bảo tồn hoàn hảo đầu ra ngay cả trên các quy trình có đầu ra phức tạp như các thanh tiến trình khi cài đặt npm. Tuyệt vời!
Dave Koo

1
Tại sao đây không phải là câu trả lời được chấp nhận? đó là người duy nhất làm việc cho tôi và nó chỉ là 2 dòng *
Lincoln

Mẹo này rất hữu ích khi thực hiện một số ứng dụng dòng lệnh Symfony sử dụng các thanh tiến trình. Chúc mừng.
Halfstop

Đây chỉ là câu trả lời được chấp nhận bởi điều duy nhất bảo tồn đại diện đầu ra hoàn hảo nó đơn giản nhất? vâng làm ơn
evnp

21

Tôi chỉ muốn thêm một vấn đề nhỏ với việc xuất các chuỗi bộ đệm từ một quy trình được sinh ra console.log()là nó thêm các dòng mới, có thể trải rộng đầu ra quá trình sinh ra của bạn trên các dòng bổ sung. Nếu bạn xuất stdouthoặc stderrvới process.stdout.write()thay console.log(), sau đó bạn sẽ nhận được giao diện điều khiển đầu ra từ quá trình sản sinh ra 'như là'.

Tôi đã thấy giải pháp đó ở đây: Node.js: in ra bàn điều khiển mà không có dòng mới?

Hy vọng rằng sẽ giúp ai đó sử dụng giải pháp ở trên (đây là một giải pháp tuyệt vời cho đầu ra trực tiếp, ngay cả khi đó là từ tài liệu).


1
Để sử dụng đầu ra chính xác hơn nữa spawn(command, args, { stdio: 'inherit' }), như được đề xuất bởi @MorganTodareyQuilling tại đây stackoverflow.com/questions/10232192/iêu
Livven

20

Lấy cảm hứng từ câu trả lời của Nathanael Smith và nhận xét của Eric Freese, nó có thể đơn giản như:

var exec = require('child_process').exec;
exec('coffee -cw my_file.coffee').stdout.pipe(process.stdout);

Điều này dường như hoạt động tốt cho các lệnh đơn giản như lsnhưng thất bại cho các lệnh phức tạp hơn như npm install. Tôi thậm chí đã thử đường ống cả stdout và stderr đến các đối tượng quá trình tương ứng của chúng.
linuxdan

@linuxdan có thể là do npm đang viết bằng stderr (tôi đã thấy một số ghi thanh tiến trình ở đó). bạn cũng có thể đặt ống stderr, hoặc mở rộng giải pháp Tongfa để nghe trên stderr.
Sergiu

@linuxdan Từ những gì tôi thấy cách đáng tin cậy nhất là spawn(command, args, { stdio: 'inherit' }), như được đề xuất ở đây stackoverflow.com/questions/10232192/ ích
Livven

12

Tôi đã thấy hữu ích khi thêm một tập lệnh exec tùy chỉnh vào các tiện ích của tôi để làm điều này.

Utility.js

const { exec } = require('child_process')

module.exports.exec = (command) => {
  const process = exec(command)

  process.stdout.on('data', (data) => {
    console.log('stdout: ' + data.toString())
  })

  process.stderr.on('data', (data) => {
    console.log('stderr: ' + data.toString())
  })

  process.on('exit', (code) => {
    console.log('child process exited with code ' + code.toString())
  })
}

app.js

const { exec } = require('./utilities.js')

exec('coffee -cw my_file.coffee')

5

Sau khi xem xét tất cả các câu trả lời khác, tôi đã kết thúc với điều này:

function oldSchoolMakeBuild(cb) {
    var makeProcess = exec('make -C ./oldSchoolMakeBuild',
         function (error, stdout, stderr) {
             stderr && console.error(stderr);
             cb(error);
        });
    makeProcess.stdout.on('data', function(data) {
        process.stdout.write('oldSchoolMakeBuild: '+ data);
    });
}

Đôi khi datasẽ có nhiều dòng, vì vậy oldSchoolMakeBuildtiêu đề sẽ xuất hiện một lần cho nhiều dòng. Nhưng điều này không làm phiền tôi đủ để thay đổi nó.


3

child_ process.spawn trả về một đối tượng với các luồng stdout và stderr. Bạn có thể nhấn vào luồng đầu ra để đọc dữ liệu mà tiến trình con gửi lại cho Nút. stdout là một luồng có "dữ liệu", "kết thúc" và các sự kiện khác mà các luồng có. spawn được sử dụng tốt nhất khi bạn muốn tiến trình con trả về một lượng lớn dữ liệu cho Node - xử lý ảnh, đọc dữ liệu nhị phân, v.v.

để bạn có thể giải quyết vấn đề của mình bằng cách sử dụng child_ process.spawn như được sử dụng dưới đây.

var spawn = require('child_process').spawn,
ls = spawn('coffee -cw my_file.coffee');

ls.stdout.on('data', function (data) {
  console.log('stdout: ' + data.toString());
});

ls.stderr.on('data', function (data) {
  console.log('stderr: ' + data.toString());
});

ls.on('exit', function (code) {
  console.log('code ' + code.toString());
});

1

Đây là một hàm trợ giúp async được viết bằng bản thảo có vẻ như là một mẹo nhỏ đối với tôi. Tôi đoán điều này sẽ không hoạt động cho các quy trình lâu dài nhưng vẫn có thể có ích cho ai đó?

import * as child_process from "child_process";

private async spawn(command: string, args: string[]): Promise<{code: number | null, result: string}> {
    return new Promise((resolve, reject) => {
        const spawn = child_process.spawn(command, args)
        let result: string
        spawn.stdout.on('data', (data: any) => {
            if (result) {
                reject(Error('Helper function does not work for long lived proccess'))
            }
            result = data.toString()
        })
        spawn.stderr.on('data', (error: any) => {
            reject(Error(error.toString()))
        })
        spawn.on('exit', code => {
            resolve({code, result})
        })
    })
}
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.