Exec: stdout "canlı" göster


188

Bu basit komut dosyası var:

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

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

burada sadece bir kahve komut dosyası derlemek için bir komut yürütmek. Ancak stdout asla konsolda görüntülenmez, çünkü komut asla sona ermez (kahvenin -w seçeneği nedeniyle). Komutu doğrudan konsoldan çalıştırırsam şöyle bir mesaj alırım:

18:05:59 - compiled my_file.coffee

Sorum şu: node.js exec ile bu mesajları görüntülemek mümkün mü? Evet ise nasıl? !

Teşekkürler


1
Buraya Python çalıştırılabilirinden stdout yakalamak için geldim. Aşağıdakilerin hepsinin işe yarayacağını, ancak kesintinin engellenmemiş olmasını sağlamak ve böylece canlı güncellemeler yapmak için python'u "-u" seçeneğiyle çalıştırmanız gerektiğini unutmayın.
Andy

Yanıtlar:


266

Kullanma exec. spawnBir EventEmmiternesne olanı kullanın . Sonra stdout/ stderrevents ( spawn.stdout.on('data',callback..)) ifadesini olduğu gibi dinleyebilirsiniz .

NodeJS belgelerinden:

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 çıktıyı arabelleğe alır ve genellikle komutun yürütülmesi bittiğinde döndürür.


22
Çok hoş. Bilginize: stdout / stderr olayları geri çağırma argümanı 'data' bir arabellektir, bu nedenle .toString () ile çağırın
SergeL

4
Windows üzerinde çalışmak için yumurtlamayanlarınız için bu harika cevaba bir göz atın .
tomekwi

17
exec aynı zamanda en azından bir EventEmitter'dir.
Nikolay Tsenkov

4
Ayrıca, program her yeni satır çıkardığında geri aramanın çağrılmayacağını da unutmayın. flush(stdout);Alt işlemden "olaylar" almak istiyorsanız , Düğümde olayları başlatmak için bu işlemin tamponu ( C cinsinden) temizlemesi gerekir.
Julian F. Weinert

5
Exec bir EventEmitter olmak +1 .. bir args dizisi (çok uzun ve karmaşık ffmpeg komut satırı) içine benim dize yeniden düzenleme üzerinde 2 saat geçirdim .. sadece gerçekten gerek yoktu öğrenmek için.
deadconversations

176

exec EventEmitter olan bir ChildProcess nesnesi de döndürür.

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

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

VEYA pipealt işlem ana stdout için stdout.

coffeeProcess.stdout.pipe(process.stdout);

VEYA spawn kullanarak stdio devral

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

35
Bu sadece kullanarak basitleştirilebilir gibi görünüyor pipe:coffeeProcess.stdout.pipe(process.stdout);
Eric Freese

3
@ EricFreese'nin yorumu aradığım şeydi, çünkü stdout'un karakterleri değiştirme özelliğinden (düğüm komut dosyasındaki
iletkiyi kullanmak

19
Daha basit: spawn(cmd, argv, { stdio: 'inherit' }). Farklı örnekler için nodejs.org/api/child_process.html#child_process_options_stdio adresine bakın .
Morgan Touverey

3
MorganTouvereyQuilling önerisi kullanmak @ +1 spawnile stdio: 'inherit'. Bu daha doğru çıktı daha üretir execve Boru stdout/ stderrbir gelen ilerleme bilgileri görüntülerken örneğin git clone.
Livven

58

Zaten birkaç cevap var, ancak hiçbiri bunu kullanmanın en iyi (ve en kolay) yolunu spawnve { stdio: 'inherit' }seçeneğini belirtmiyor . En doğru çıktıyı, örneğin a git clone.

Sadece bunu yapın:

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

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

@MorganTouvereyQuilling'e bu yorumda işaret ettiği için teşekkür ederiz .


1
Alt süreç renkli metin gibi biçimlendirilmiş çıktı kullandığında, stdio: "inherit"bu biçimlendirmeyi korumasa da korur child.stdout.pipe(process.stdout).
Rikki Gibson

Bu, npm kurulumlarındaki ilerleme çubukları gibi karmaşık çıktıya sahip işlemlerde bile çıktıyı mükemmel şekilde korur. Müthiş!
Dave Koo

1
neden bu kabul edilen cevap değil? benim için çalıştı sadece biriydi ve sadece 2 f * hatları !!!
Lincoln

Bu ipucu, ilerleme çubukları kullanan bazı Symfony komut satırı uygulamalarını yürütürken yardımcı oldu. Şerefe.
Halfstop

Bu, mükemmel çıktı sunumunu koruyan kabul edilen cevap - tek şey olmalı ve bu en basit olanı mı? evet lütfen
evnp

21

Ben sadece bir spawned süreçten tampon dizeleri çıktısı ile küçük bir sorun eklemek için console.log()yeni satırlar eklemek olduğunu , hangi spawned süreç çıkış ek satırları üzerine yaymak olduğunu. Size çıkış ise stdoutya stderrbirlikte process.stdout.write()yerine console.log(), o zaman 'olduğu gibi' olurken süreçten konsol çıktısını alırsınız.

Bu çözümü burada gördüm: Node.js: sondaki yeni satır olmadan konsola mı yazdırıyorsunuz?

Umarım yukarıdaki çözümü kullanan birisine yardımcı olur (bu, dokümantasyondan olsa bile canlı çıktı için harika bir çözümdür).


1
spawn(command, args, { stdio: 'inherit' })@MorganTouvereyQuilling here tarafından önerildiği gibi daha da doğru çıktı kullanımı için stackoverflow.com/questions/10232192/…
Livven

21

Nathanael Smith'in cevabı ve Eric Freese'nin yorumundan esinlenerek şöyle olabilir:

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

Bu gibi basit komutlar için iyi çalışıyor gibi görünüyor, lsancak gibi daha karmaşık komutlar için başarısız npm install. Hatta kendi stdout ve stderr kendi işlem nesnelerine boru denedim.
linuxdan

@linuxdan olabilir çünkü npm stderr yazıyor (bazı ilerleme çubuğu orada yazma gördüm). Ayrıca stderr'i borulayabilir veya stderr'ı dinlemek için Tongfa çözümünü genişletebilirsiniz.
Sergiu

@linuxdan En güvenilir yoldan gördüğüm kadarıyla spawn(command, args, { stdio: 'inherit' }), burada önerildiği gibi stackoverflow.com/questions/10232192/…
Livven

En iyi cevap, bunun için teşekkürler. Bir cazibe gibi çalıştı
Abhishek Sharma

12

Bunu yapan yardımcı programları için özel bir exec komut dosyası eklemek yararlı buldum.

utilities.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

Diğer tüm cevapları inceledikten sonra bununla sonuçlandım:

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

Bazen databirden çok satır olur, bu nedenle oldSchoolMakeBuildbaşlık birden çok satır için bir kez görünür. Ama bu beni değiştirecek kadar rahatsız etmedi.


3

child_process.spawn, stdout ve stderr akışlarına sahip bir nesne döndürür. Alt işlemin Düğüme geri gönderdiği verileri okumak için stdout akışına dokunabilirsiniz. stdout'un bir akış olması "veri", "son" ve akışların sahip olduğu diğer olaylara sahiptir. spawn en iyi, alt işlemin Düğüm'e büyük miktarda veri döndürmesini istediğinizde kullanılır - görüntü işleme, ikili verileri okuma vb.

böylece probleminizi aşağıdaki gibi child_process.spawn kullanarak çözebilirsiniz.

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

İşte benim için hile gibi görünüyor daktiloda yazılmış bir asenkron yardımcı işlevi. Sanırım bu uzun ömürlü süreçler için işe yaramayacak ama yine de birisi için kullanışlı olabilir mi?

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})
        })
    })
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.