1
votes

Node.js spawn: conservez StdOut et StdErr dans l'ordre d'origine

Essayer d'exécuter le script batch Windows à partir de node.js v12.6.0 et de capturer sa sortie en temps réel et dans le bon ordre.

Mais l'ordre de stdout et stderr est autre (pas toujours, mais dans 80% des cas) mélangé pendant les tests.

Comment garder stdout et stderr dans l'ordre d'origine?


Voici l'extrait de code JavaScript que j'utilise pour les tests:

child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);


0 commentaires

3 Réponses :


0
votes

Malheureusement, vous ne pouvez pas garantir la commande.

Ce sont des canaux différents avec une mise en mémoire tampon et un comportement indépendants. Le shell lui-même obtiendra parfois des messages STDERR / STDOUT dans l'ordre prévu. Ceci est également typique d'autres applications, même en dehors de Node.js.


1 commentaires

Oui, j'ai également rencontré ce problème dans diverses autres applications. Néanmoins, cela fonctionne de manière fiable dans certains cas (voir EDIT 1), mais la capture de la sortie devient alors un problème.



0
votes

Si vous n'avez pas besoin de faire la distinction entre STDOUT et STDERR, vous pouvez les joindre à la source (dans le fichier batch). Le fichier de commandes renvoie alors tous les STDERR et STDOUT uniquement en tant que STDOUT

@Echo Off
ChCp 65001 >Nul
(
Echo 1 [stdout] ...
Echo 2 [stderr] ... 1>&2
Echo 3 [stderr] ... 1>&2
Echo 4 [stdout] ...
Echo 5 [stdout] ...
Echo 6 [stderr] ... 1>&2
) 2>&1


1 commentaires

Merci, cela fonctionne, et je n'ai pas vraiment besoin de distinguer les messages, mais dans ce script de test par lots, ce n'est qu'un exemple. Mon objectif final est d'essayer d'utiliser node.js pour l'automatisation de Windows (y compris le démarrage de différents processus et le traitement de la sortie). Malheureusement, pour l'instant, cela semble être une mauvaise idée.



2
votes

Sans modifier le fichier exécutable, une approche acceptable peut être (notez les options de spawn et les arguments de commande):

const readline = require('readline');

// ...

const lineReader = readline.createInterface({
    input: child.stdout
});

lineReader.on('line', (line) => {
    if (line.includes('[ERROR]:')) {
        console.error(line); // StdErr.
    } else {
        console.log(line);   // StdOut.
    }
});

Cependant, elle présente quelques inconvénients:

  1. Cela génère une instance de processus de console supplémentaire.
  2. Si vous souhaitez utiliser le paramètre d'options de spawn 'windowsHide: true' pour masquer l'application avec l'interface graphique, évitez de démarrer le processus avec le paramètre 'shell: true', car seule la fenêtre de la console sera masquée, pas la fenêtre de l'application cible. li >
  3. Vous ne pouvez pas distinguer StdOut et StdErr. Selon le format de sortie de l'application cible, la solution à ce problème peut ressembler à ceci:
const { spawn } = require('child_process');

const options = {
    shell: true,
    stdio: [
        'inherit', // StdIn.
        'pipe',    // StdOut.
        'pipe',    // StdErr.
    ],
};

const child = spawn('exectest.cmd', ['2>&1'], options);

let mergedOut = '';

child.stdout.setEncoding('utf8');
child.stdout.on('data', (chunk) => {
    process.stdout.write(chunk, (_err) => { });
    mergedOut += chunk;
});

child.on('close', (_code, _signal) => {
    console.log('-'.repeat(30));
    console.log(mergedOut);
});


0 commentaires