2013-03-11 32 views
12

aşağıdaki C programını (test.c) düşünün akışları: stdout'a bir çizgi yazdırmalısınıznode.js

#include <stdio.h> 

int main() { 
    printf("string out 1\n"); 
    fprintf(stderr, "string err 1\n"); 
    getchar(); 
    printf("string out 2\n"); 
    fprintf(stderr, "string err 2\n"); 
    fclose(stdout); 
} 

bir çizgi stderr bekletin kullanıcı girişi için, stdout'a başka bir satır ve stderr'e başka bir satır. Çok basit! derlenmiş ve tam (kullanıcı girişi getchar için alınır)() ne zaman komut satırında programın çıktısını çalıştırdığınızda:

$ ./test 
string out 1 
string err 1 

string out 2 
string err 2 

aşağıdaki kodla nodejs ile çocuk süreç olarak bu programı yumurtlamaya çalışırken :

var TEST_EXEC = './test'; 

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

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

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

// Simulate entering data for getchar() after 1 second 
setTimeout(function() { 
    test.stdin.write('\n'); 
}, 1000); 

çıktı gibi görünür:

terminal seçenekleri içinde ./test çalıştırırken görüldüğü gibi çıktı çok farklı
$ nodejs test.js 
stderr: string err 1 

stdout: string out 1 
string out 2 

stderr: string err 2 

l. Bunun nedeni,. /test programının nodejs tarafından oluşturulduğunda etkileşimli bir kabukta çalışmadığıdır. Test.c stdout akışı arabelleğe alınır ve bir \ n'ye ulaşılır ulaşmaz terminalde çalıştırıldığında arabelleği temizlenir, ancak bu şekilde düğümle birlikte oluşturulduğunda arabellek temizlenmez. Bu, her baskıdan sonra stdout'u temizleyerek veya arabelleğe alınacak stdout akışını değiştirerek çözülebilir, böylece her şeyi anında temizler. Test.c kaynağının mevcut olmadığını veya değiştirilemeyeceğini varsayarsak, belirtilen iki yıkama seçeneğinin hiçbiri uygulanamaz.

var spawn = require('pty.js').spawn; 
var test = spawn(TEST_EXEC); 

test.on('data', function (data) { 
    console.log('data: ' + data); 
}); 

// Simulate entering data for getchar() after 1 second 
setTimeout(function() { 
    test.write('\n'); 
}, 1000); 

verir:

$ nodejs test.js 
data: string out 1 
string err 1 

data: 

data: string out 2 
string err 2 

Ancak hem

Sonra örneğin, iyi bir iş pty.js (sözde terminali) var, interaktif bir kabuk taklit bakmaya başladı stdout ve stderr (bir terminalde programı çalıştırırken göreceğiniz gibi) birleştirilir ve verileri akışlardan ayırmanın bir yolunu düşünemiyorum.

Yani soru ..

test.c kodunuzu değiştirmeden ./test çalıştırırken görüldüğü gibi sonuç elde etmek için nodejs kullanarak herhangi bir yolu var mı? Terminal emülasyonu veya süreç yumurtlama veya başka bir yöntem ile?

Şerefe!

+0

Sorunun açıklamasına büyük miktarda çaba harcadığınız için teşekkür ederiz! Bir başkasının python betiğini düğümünden çalıştırırken aynı problemi yaşadım, ancak temeldeki arabelleğe alma mekaniği hakkında hiçbir şey bilmiyordum. Görünüşe göre (benim python becerilerim varolmayan +/-), sadece 'python -u' kullanıldığında arabelleğe alınmamış IO ve problemimi çözdüm! – Matthias

+0

@gratz Bu problemi çözdünüz mü? Ben benzer bir sorunla karşılaşıyorum. Bunu http://stackoverflow.com/questions/42130677/how-to-get-mongo-shell-outputthree-dot-for-unterminated-command –

cevap

2

Şimdi 5.7.0 sürümünden beri düğümde bulunan yumurtlama komutu için bir 'kabuk' seçeneği mevcut olduğundan bunu tekrar ziyaret ettim. Ne yazık ki, interaktif kabuğunu (shell: '/bin/sh -i' ile denedim ama sevinç yok) oluşturmak için bir seçenek görünmüyor. Ancak, sadece çalıştırmak istediğiniz programın tamponlama seçeneklerini değiştirmenize izin veren 'stdbuf' kullanılmasını öneren this'u buldum. Onları her şeyde 0'a ayarlamak, tüm akışlar için arabelleğe alınmamış çıktı üretir ve hala ayrı tutulurlar. gerçi benzer alternatifler olabilir bu OSX ve Windows için mevcut değil elbette önceden yüklü değil gibi

var TEST_EXEC = './test'; 

var spawn = require('child_process').spawn; 
var test = spawn('stdbuf', ['-i0', '-o0', '-e0', TEST_EXEC]); 

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

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

// Simulate entering data for getchar() after 1 second 
setTimeout(function() { 
    test.stdin.write('\n'); 
}, 1000); 

görünüyor:

İşte güncellenen javascript var.

+1

Bu 'stdbuf' hile çözdü Sorun Ben bir yumurtlu kabuk içinde çalışan bir komut stdout buffering ile vardı (Düğüm v0.10.29 Raspbian Jessie kullanarak).Çok teşekkürler, gratz! – mvanallen

+0

Bu yardımcı oldu – gratz

2

Bunu yapabilirsin:

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

test.stdin.pipe(process.stdin); 
test.stdout.pipe(process.stdout); 
test.stderr.pipe(process.stderr); 

Eğer console.log üzerine çıktı yazdırmak için stdout ve stderr etkinlikleri kullanmak

, sen çünkü fonksiyonların asenkron yürütme karmakarışık çıkışını alacak. Çıkış bağımsız olarak bir akış için sıralanacaktır, ancak çıkış hala stdin, stdout ve stderr arasında araya girebilir.

+0

adresinden yapabilirsiniz. Bir şeyi kaçırmadıkça, çıktıları nasıl programlanabilir olarak kullanabilirim? Böylece? – gratz

+0

'Test' standart akışlarını, 'a' sürecini (burada düğümün kendisi), başka bir prosese pipetleyebilirsiniz. – user568109

+0

Ama bir '\ n' ulaştığında sınama almak için, işlem, bir interaktif kabukta çalıştığı sanki sınamak boruları temizlemek için bir terminal veya pseudo terminal (pty) olması gerekirdi. Yukarıdaki örneklerde olduğu gibi stdout ve stderr arasındaki farkı kaybetmek anlamına mı geliyor? – gratz

11

Kullanıcı568109 tarafından yanıtı denedim, ancak bu çalışmaz, bu yalnızca akışlar arasındaki veriyi kopyaladığından dolayı anlam ifade etmiyor. Bu nedenle, yalnızca arabellek temizlendiğinde işlem görecek. şu işe görüntülenir: Bu etkili bir düğüm süreci ile stdio hisseleri

var TEST_EXEC = './test'; 

var spawn = require('child_process').spawn; 
var test = spawn(TEST_EXEC, [], { stdio: 'inherit' }); 

//the following is unfortunately not working 
//test.stdout.on('data', function (data) { 
// console.log('stdout: ' + data); 
//}); 

Not söyledi. Bununla yaşayabileceğinden emin değilim.

+1

'' seçeneğiyle 'spawn()' özelliğini kullanma '{stdio: 'devralır'} 'aslında ana akımlara araya sokulmuş çıktıyı sağlar, ama - en azından '0.10.10' - ** 'dan itibaren - olaylar üzerinden akışlarda" dinleme "yeteneğini kaybedersiniz **: alt işlem nesnelerinde ".stdin", ".stdout", .stderr 'özelliklerini yeniden kullanır:" Çocuk stdio akışları ebeveynle paylaşılırsa, bu ayarlanmaz. "http: // nodejs .org/aPI/child_process.html # child_proces s_child_stdout. Başka bir deyişle: 0.10.10 itibariyle, kodunuz '.stdout' özelliğine erişirken başarısız olur. Bunu düzeltirsen cevabını +1 sevinirim. – mklement0

+0

Haklısınız! Bu berbat; Ben process.stdout gibi bir yazılabilir akışında bir 'veri' olayı gibi bir şey olduğunu sanmıyorum, bu yüzden bu çıkışa bir şekilde ulaşıp ulaşamayacağınızı bilmiyorum :-(spawn'u paylaştığınız için – Matthias

+3

+1() '+ stdio: 'inherit'} tekniği (OP'nin problemini çözmese de) Yazmayı dinlerken: birisi süreç için bir çözüm buldu * sürecin“ alt sınıflaması ” .stdout.write() 'yöntemi, ancak, ne yazık ki, ne * çocuk * süreçleri paylaşılan akışları yazmak için çalışmıyor: https://gist.github.com/bsatrom/1349384 – mklement0