J'essaie toujours de saisir les subtilités de la façon dont je peux exécuter une commande Linux ou Windows Shell et capturer la sortie dans node.js; finalement, je veux faire quelque chose comme ça ...
//pseudocode
output = run_command(cmd, args)
L'élément important est qu'il output
doit être disponible pour une variable (ou un objet) à portée globale. J'ai essayé la fonction suivante, mais pour une raison quelconque, je suis undefined
imprimé sur la console ...
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" <------
J'ai du mal à comprendre où se situe le code ci-dessus ... un prototype très simple de ce modèle fonctionne ...
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" <----
Quelqu'un peut-il m'aider à comprendre pourquoi try_this()
fonctionne et run_cmd()
ne fonctionne pas? FWIW, je dois utiliser child_process.spawn
, car child_process.exec
a une limite de tampon de 200 Ko.
Résolution finale
J'accepte la réponse de James White, mais c'est le code exact qui a fonctionné pour moi ...
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);
la source
me.stdout = "";
danscmd_exec()
pour éviter concaténerundefined
au début du résultat.Réponses:
Il y a trois problèmes ici qui doivent être résolus:
Tout d'abord , vous vous attendez à un comportement synchrone lors de l'utilisation asynchrone de stdout. Tous les appels de votre
run_cmd
fonction sont asynchrones, donc il engendrera le processus enfant et retournera immédiatement indépendamment du fait que certaines, toutes ou aucune des données aient été lues sur stdout. En tant que tel, lorsque vous courezvous obtenez tout ce qui se trouve être stocké dans foo.stdout pour le moment, et il n'y a aucune garantie de ce que ce sera parce que votre processus enfant est peut-être toujours en cours d'exécution.
Deuxièmement , stdout est un flux lisible , donc 1) l'événement de données peut être appelé plusieurs fois, et 2) le rappel reçoit un tampon, pas une chaîne. Facile à remédier; juste changer
dans
afin que nous convertissions notre tampon en une chaîne et ajoutions cette chaîne à notre variable stdout.
Troisièmement , vous ne pouvez savoir que vous avez reçu toute la sortie lorsque vous obtenez l'événement 'end', ce qui signifie que nous avons besoin d'un autre auditeur et d'un autre rappel:
Donc, votre résultat final est le suivant:
la source
this.stdout = "";
à l'intérieur de larun()
fonction, sinon votreconsole.log(foo.sdtout);
sera préfixé avecundefined
.Une version simplifiée de la réponse acceptée (troisième point), a juste fonctionné pour moi.
Usage:
la source
child.stdout.on('close', (errCode) => { console.log(errCode) } )
J'ai utilisé ceci de manière plus concise:
cela fonctionne parfaitement. :)
la source
sys.puts()
était obsolète en 2011 (avec Node.js v0.2.3). Vous devriez utiliser à laconsole.log()
place.Le moyen le plus simple est d'utiliser simplement la lib ShellJS ...
Exemple EXEC:
ShellJs.org prend en charge de nombreuses commandes shell courantes mappées en tant que fonctions NodeJS, notamment:
la source
shell.exec("foo.sh arg1 arg2 ... ")
. Votrefoo.sh
script peut les référencer en utilisant$1
,$2
... etc.J'ai eu un problème similaire et j'ai fini par écrire une extension de nœud pour cela. Vous pouvez extraire le référentiel git. C'est open source et gratuit et toutes ces bonnes choses!
https://github.com/aponxi/npm-execxi
Les instructions d'utilisation se trouvent dans le fichier ReadMe . N'hésitez pas à faire des pull requests ou à soumettre des problèmes!
J'ai pensé qu'il valait la peine de le mentionner.
la source
@ TonyO'Hagan est une
shelljs
réponse complète , mais je voudrais souligner la version synchrone de sa réponse:la source
Monotouche synchrone:
require('child_process').execSync("echo 'hi'", function puts(error, stdout, stderr) { console.log(stdout) });
la source
Il y a un conflit de variable dans votre
run_cmd
fonction:Changez-le simplement en ceci:
Afin de voir les erreurs, ajoutez toujours ceci:
EDIT Votre code échoue parce que vous essayez d'exécuter
dir
ce qui n'est pas fourni en tant que programme autonome séparé. C'est une commande encmd
cours. Si vous voulez jouer avec le système de fichiers, utilisez natifrequire( 'fs' )
.Alternativement (ce que je ne recommande pas) vous pouvez créer un fichier batch que vous pouvez ensuite exécuter. Notez que le système d'exploitation déclenche par défaut les fichiers de commandes via
cmd
.la source
C:\Windows\System32\netstat.exe
, cela ne donne toujours pas de résultats ... Ma syntaxe exacte étaitfoo = new run_cmd('netstat.exe', ['-an'], function (me, data){me.stdout=data;});
... J'ai également essayé le chemin complet sans succès jusqu'à présentVous ne retournez rien de votre fonction run_cmd.
Fonctionne très bien. :)
la source
return
soit nécessaire tant que vous définissez correctement les attributs de l'objetUne version promis de la réponse la plus récompensée:
Utiliser:
la source