Nadal próbuję uchwycić szczegóły, w jaki sposób mogę uruchomić polecenie powłoki systemu Linux lub Windows i przechwytywać dane wyjściowe w node.js; ostatecznie chcę zrobić coś takiego ...
//pseudocode
output = run_command(cmd, args)
Ważnym elementem jest to, że output
musi być dostępny dla zmiennej (lub obiektu) o zasięgu globalnym. Wypróbowałem następującą funkcję, ale z jakiegoś powodu wyświetla się undefined
na konsoli ...
function run_cmd(cmd, args, cb) {
var spawn = require('child_process').spawn
var child = spawn(cmd, args);
var me = this;
child.stdout.on('data', function(me, data) {
cb(me, data);
});
}
foo = new run_cmd('dir', ['/B'], function (me, data){me.stdout=data;});
console.log(foo.stdout); // yields "undefined" <------
Mam problem ze zrozumieniem, gdzie powyższy kod się psuje ... działa bardzo prosty prototyp tego modelu ...
function try_this(cmd, cb) {
var me = this;
cb(me, cmd)
}
bar = new try_this('guacamole', function (me, cmd){me.output=cmd;})
console.log(bar.output); // yields "guacamole" <----
Czy ktoś może mi pomóc zrozumieć, dlaczego try_this()
działa, a run_cmd()
nie? FWIW, muszę użyć child_process.spawn
, ponieważ child_process.exec
ma limit bufora 200KB.
Ostateczna rozdzielczość
Przyjmuję odpowiedź Jamesa White'a, ale to jest dokładny kod, który zadziałał dla mnie ...
function cmd_exec(cmd, args, cb_stdout, cb_end) {
var spawn = require('child_process').spawn,
child = spawn(cmd, args),
me = this;
me.exit = 0; // Send a cb to set 1 when cmd exits
me.stdout = "";
child.stdout.on('data', function (data) { cb_stdout(me, data) });
child.stdout.on('end', function () { cb_end(me) });
}
foo = new cmd_exec('netstat', ['-rn'],
function (me, data) {me.stdout += data.toString();},
function (me) {me.exit = 1;}
);
function log_console() {
console.log(foo.stdout);
}
setTimeout(
// wait 0.25 seconds and print the output
log_console,
250);
javascript
node.js
shell
Mike Pennington
źródło
źródło
me.stdout = "";
wcmd_exec()
celu zapobieżenia złączenieundefined
na początku związku.Odpowiedzi:
Istnieją trzy problemy, które należy naprawić:
Po pierwsze , oczekujesz zachowania synchronicznego podczas asynchronicznego używania standardowego wyjścia. Wszystkie wywołania w twojej
run_cmd
funkcji są asynchroniczne, więc spowoduje to powstanie procesu potomnego i natychmiastowe zwrócenie, niezależnie od tego, czy niektóre, wszystkie czy żadne dane nie zostały odczytane ze standardowego wyjścia. Jako takie, kiedy biegaszdostajesz wszystko, co jest obecnie przechowywane w foo.stdout i nie ma gwarancji, co to będzie, ponieważ Twój proces potomny może nadal działać.
Po drugie , stdout jest strumieniem , który można odczytać , więc 1) zdarzenie danych można wywołać wiele razy, a 2) wywołanie zwrotne otrzymuje bufor, a nie łańcuch. Łatwe do naprawienia; po prostu zmień
w
więc konwertujemy nasz bufor na łańcuch i dodajemy ten ciąg do naszej zmiennej stdout.
Po trzecie , możesz wiedzieć, że otrzymałeś wszystkie dane wyjściowe tylko wtedy, gdy otrzymasz zdarzenie 'end', co oznacza, że potrzebujemy innego nasłuchiwania i wywołania zwrotnego:
Tak więc ostateczny wynik jest następujący:
źródło
this.stdout = "";
wewnątrzrun()
funkcji, w przeciwnym razie twójconsole.log(foo.sdtout);
będzie poprzedzony przedrostkiemundefined
.Uproszczona wersja zaakceptowanej odpowiedzi (trzeci punkt) po prostu zadziałała.
Stosowanie:
źródło
child.stdout.on('close', (errCode) => { console.log(errCode) } )
Użyłem tego bardziej zwięźle:
działa idealnie. :)
źródło
sys.puts()
został wycofany w 2011 roku (z Node.js v0.2.3). Zamiast tego powinieneś użyćconsole.log()
.Najprostszym sposobem jest użycie biblioteki ShellJS ...
Przykład EXEC:
ShellJs.org obsługuje wiele popularnych poleceń powłoki odwzorowanych jako funkcje NodeJS, w tym:
źródło
shell.exec("foo.sh arg1 arg2 ... ")
. Twójfoo.sh
skrypt może odwołać je za pomocą$1
,$2
... itd.Miałem podobny problem i napisałem do tego rozszerzenie węzła. Możesz sprawdzić repozytorium git. To open source, darmowe i wszystkie dobre rzeczy!
https://github.com/aponxi/npm-execxi
Instrukcje użytkowania znajdują się w pliku ReadMe . Zapraszam do składania żądań ściągnięcia lub zgłaszania problemów!
Pomyślałem, że warto o tym wspomnieć.
źródło
@ TonyO'Hagan to kompleksowa
shelljs
odpowiedź, ale chciałbym podkreślić synchroniczną wersję jego odpowiedzi:źródło
Synchroniczna jednowarstwowa:
require('child_process').execSync("echo 'hi'", function puts(error, stdout, stderr) { console.log(stdout) });
źródło
W Twojej
run_cmd
funkcji występuje konflikt zmiennych :Po prostu zmień to na to:
Aby zobaczyć błędy, zawsze dodaj to:
EDYCJA Twój kod nie powiódł się, ponieważ próbujesz uruchomić,
dir
co nie jest dostarczane jako oddzielny program autonomiczny. To polecenie wcmd
toku. Jeśli chcesz grać z systemem plików, użyj natywnegorequire( 'fs' )
.Alternatywnie (czego nie polecam) możesz utworzyć plik wsadowy, który możesz następnie uruchomić. Zauważ, że system operacyjny domyślnie uruchamia pliki wsadowe za pośrednictwem
cmd
.źródło
C:\Windows\System32\netstat.exe
, to nadal nie daje rezultatów ... Moja dokładna składnia byłafoo = new run_cmd('netstat.exe', ['-an'], function (me, data){me.stdout=data;});
... Próbowałem też pełnej ścieżki bez powodzeniaW rzeczywistości nie zwracasz niczego z funkcji run_cmd.
Działa dobrze. :)
źródło
return
jest to wymagane, o ile poprawnie ustawisz atrybuty obiektuObiecana wersja najczęściej nagradzanej odpowiedzi:
Używać:
źródło