web-dev-qa-db-fra.com

Exécution d'une commande Shell à partir de Node.js sans mise en mémoire tampon de la sortie

J'essaie de lancer une commande Shell à partir de Node.js, sans redirigeant l'entrée et la sortie de cette commande - tout comme la décortiquer vers une commande en utilisant un script Shell ou en utilisant Ruby's system commande. Si le processus enfant veut écrire dans STDOUT, je veux que cela aille directement à la console (ou soit redirigé, si ma Node a été redirigée).

Node ne semble pas avoir de moyen simple de le faire. Il semble que la seule façon d'exécuter un autre processus soit avec child_process, Qui toujours redirige l'entrée et la sortie du processus enfant vers des canaux. Je peux écrire du code pour accepter les données de ces canaux et les écrire dans les STDOUT et STDERR de mon processus, mais si je le fais, les API me forcent à sacrifier une certaine flexibilité.

Je veux deux fonctionnalités:

  • Syntaxe du shell. Je veux pouvoir diriger la sortie entre les commandes ou exécuter des fichiers batch Windows.
  • Sortie illimitée. Si je bombarde un compilateur et qu'il veut générer des mégaoctets d'avertissements du compilateur, je veux qu'ils défilent sur l'écran (jusqu'à ce que l'utilisateur en ait marre et frappe Ctrl + C).

Il ressemble à Node veut me forcer à choisir entre ces deux fonctionnalités.

  • Si je veux une quantité illimitée de sortie, je peux utiliser child_process.spawn puis faire child.stdout.on('data', function(data) { process.stdout.write(data); }); et la même chose pour stderr, et c'est ' Je transmettrai avec plaisir les données jusqu'à ce que les vaches rentrent à la maison. Malheureusement, spawn ne prend pas en charge la syntaxe Shell.
  • Si je veux la syntaxe Shell, je peux utiliser child_process.exec . Mais exec insiste pour mettre en mémoire tampon les STDOUT et STDERR du processus enfant pour moi et me les donner à la fin, et cela limite la taille de ces tampons (configurable, 200 Ko par défaut). Je peux toujours accrocher les événements on('data'), si je veux voir la sortie telle qu'elle est générée, mais exec ajoutera toujours les données à ses tampons aussi. Lorsque la quantité de données dépasse la taille de tampon prédéfinie, exec mettra fin au processus enfant.

(Il y a aussi child_process.execFile , qui est le pire des deux mondes du point de vue de la flexibilité: pas de syntaxe Shell, mais vous devez encore plafonner le montant de sortie que vous attendez.)

Suis-je en train de manquer quelque chose? Existe-t-il un moyen de simplement Shell vers un processus enfant dans Node, et pas rediriger ses entrées et sorties? Quelque chose qui prend en charge la syntaxe Shell et qui ne s'emballe pas après une quantité prédéfinie de sortie, tout comme est disponible dans les scripts Shell, Ruby, etc.?

52
Joe White

Vous pouvez hériter des flux stdin/out/error via l'argument spawn, vous n'avez donc pas besoin de les diriger manuellement:

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

Utiliser Shell pour la syntaxe Shell - pour bash c'est -c paramètre pour lire le script à partir de la chaîne:

var spawn = require('child_process').spawn;
var shellSyntaxCommand = 'ls -l | grep test | wc -c';
spawn('sh', ['-c', shellSyntaxCommand], { stdio: 'inherit' });

Pour résumer:

var spawn = require('child_process').spawn;
function shspawn(command) {
   spawn('sh', ['-c', command], { stdio: 'inherit' });
} 

shspawn('ls -l | grep test | wc -c');
42
Andrey Sidorov

Vous pouvez remplacer exec par spawn et utiliser la syntaxe Shell simplement avec:

const {spawn} = require ('child_process');
const cmd = 'ls -l | grep test | wc -c';
const p = spawn (cmd, [], {Shell: true});

p.stdout.on ('data', (data) => {
  console.log (data.toString ());
});

La magie est juste {Shell: true}.

6
Skywalker13

Je ne l'ai pas utilisé, mais j'ai vu cette bibliothèque: https://github.com/polotek/procstreams

Si tu fais ça. La .out() redirige automatiquement vers la sortie/stdin du processus.

var $p = require('procstreams');
$p('cat lines.txt').pipe('wc -l').out();

Si ne supporte pas la syntaxe Shell, mais c'est assez trivial je pense.

var command_str = "cat lines.txt | wc -l";
var cmds = command_str.split(/\s?\|\s?/);
var cmd = $p(cmds.shift());
while(cmds.length) cmd = cmd.pipe(cmds.shift());
cmd
  .out()
  .on('exit', function() {
    // Do whatever
  });
4
loganfsmyth

Il y a un exemple dans le node ​​docs pour le module child_process:

Exemple de détachement d'un processus de longue durée et de redirection de sa sortie vers un fichier:

 var fs = require('fs'),
     spawn = require('child_process').spawn,
     out = fs.openSync('./out.log', 'a'),
     err = fs.openSync('./out.log', 'a');

 var child = spawn('prg', [], {
   detached: true,
   stdio: [ 'ignore', out, err ]
 });

 child.unref();
0
darelf