web-dev-qa-db-fra.com

node.js exécute la commande système de manière synchrone

J'ai besoin de node.js fonction

result = execSync('node -v');

cela va de manière synchrone exécuter la ligne de commande donnée et renvoyer tous les caractères stdout'ed de ce texte de commande.

ps. La synchronisation est fausse. Je connais. Juste pour un usage personnel.

UPDATE

Nous avons maintenant la solution de mgutz qui nous donne le code de sortie, mais pas la sortie standard! J'attends toujours une réponse plus précise.

UPDATE

mgutz a mis à jour sa réponse et la solution est la suivante :)
En outre, comme dgo.a est mentionné, il existe un module autonome exec-sync

MISE À JOUR 2014-07-30

ShellJS lib est arrivé. Considérez que c'est le meilleur choix pour le moment.


MISE À JOUR 2015-02-10

ENFIN! NodeJS 0.12 supporte execSync de manière native.
Voir plus haut docs

161
disfated

Node.js (depuis la version 0.12 - donc pendant un moment) supporte execSync :

child_process.execSync(command[, options])

Vous pouvez maintenant faire ceci directement:

const execSync = require('child_process').execSync;
code = execSync('node -v');

et ça fera ce que vous attendez. (Par défaut, les résultats d'entrée/sortie sont redirigés vers le processus parent). Notez que vous pouvez également spawnSync maintenant.

128
Benjamin Gruenbaum

Voir execSync bibliothèque.

C'est assez facile à faire avec node-ffi . Je ne le recommanderais pas pour les processus de serveur, mais pour les utilitaires de développement généraux, cela permet de faire avancer les choses. Installez la bibliothèque.

npm install node-ffi

Exemple de script:

var FFI = require("node-ffi");
var libc = new FFI.Library(null, {
  "system": ["int32", ["string"]]
});

var run = libc.system;
run("echo $USER");

[EDIT juin 2012: Comment obtenir STDOUT]

var lib = ffi.Library(null, {
    // FILE* popen(char* cmd, char* mode);
    popen: ['pointer', ['string', 'string']],

    // void pclose(FILE* fp);
    pclose: ['void', [ 'pointer']],

    // char* fgets(char* buff, int buff, in)
    fgets: ['string', ['string', 'int','pointer']]
});

function execSync(cmd) {
  var
    buffer = new Buffer(1024),
    result = "",
    fp = lib.popen(cmd, 'r');

  if (!fp) throw new Error('execSync error: '+cmd);

  while(lib.fgets(buffer, 1024, fp)) {
    result += buffer.readCString();
  };
  lib.pclose(fp);

  return result;
}

console.log(execSync('echo $HOME'));
54
mgutz

Utilisez le module ShellJS .

exec fonction sans fournir de rappel.

Exemple:

var version = exec('node -v').output;
31
falko

Il y a un excellent module de contrôle de flux dans node.js appelé asyncblock . Si insérer le code dans une fonction est acceptable pour votre cas, l'exemple suivant peut être pris en compte:

var asyncblock = require('asyncblock');
var exec = require('child_process').exec;

asyncblock(function (flow) {
    exec('node -v', flow.add());
    result = flow.wait();
    console.log(result);    // There'll be trailing \n in the output

    // Some other jobs
    console.log('More results like if it were sync...');
});
23
nab

Ce n'est pas possible dans Node.js, child_process.spawn et child_process.exec ont été construits à partir du sol pour être asynchrones.

Pour plus de détails, voir: https://github.com/ry/node/blob/master/lib/child_process.js

Si vous voulez vraiment avoir ce blocage, puis mettez tout ce qui doit se passer après dans un rappel, ou créez votre propre file d'attente pour le gérer de manière bloquante, je suppose que vous pourriez utiliser Async.js pour cette tâche.

Ou, au cas où vous auriez trop de temps à dépenser, lancez-vous dans Node.js.

11
Ivo Wetzel

C'est le moyen le plus simple que j'ai trouvé:

exec-Sync : https://github.com/jeremyfa/node-exec-sync
(À ne pas confondre avec execSync.)
Exécuter la commande shell de manière synchrone. Utilisez cette option pour les scripts de migration et les programmes CLI, mais pas pour le code serveur standard.

Exemple:

var execSync = require('exec-sync');   
var user = execSync('echo $USER');
console.log(user);
9
dgo.a

Juste pour ajouter que même s'il y a peu de cas d'utilisation où vous devriez les utiliser, spawnSync/execFileSync/execSync ont été ajoutés à node.js dans ces commits: https://github.com/joyent/node/compare/d58c206862dc...e8df2676748e

7
kvz

Vous pouvez y parvenir en utilisant des fibres. Par exemple, en utilisant ma bibliothèque Common Node _ , le code ressemblerait à ceci:

result = require('subprocess').command('node -v');
5
Oleg

Je m'habitue à implémenter des éléments "synchronous" à la fin de la fonction de rappel. Pas très gentil, mais ça marche. Si vous devez implémenter une séquence d'exécutions en ligne de commande, vous devez envelopper exec dans une fonction nommée et l'appeler de manière récursive. Ce modèle semble être utilisable pour moi:

SeqOfExec(someParam);

function SeqOfExec(somepParam) {
    // some stuff
    // .....
    // .....

    var execStr = "yourExecString";
    child_proc.exec(execStr, function (error, stdout, stderr) {
        if (error != null) {
            if (stdout) {
                throw Error("Smth goes wrong" + error);
            } else {
                // consider that empty stdout causes
                // creation of error object
            }
        }
        // some stuff
        // .....
        // .....

        // you also need some flag which will signal that you 
        // need to end loop
        if (someFlag ) {
            // your synch stuff after all execs
            // here
            // .....
        } else {
            SeqOfExec(someAnotherParam);
        }
    });
};
3
scherka

J'ai eu un problème similaire et j'ai fini par écrire une extension de noeud pour cela. Vous pouvez consulter le référentiel git. C'est open source et gratuit et tout ce qui est bon!

https://github.com/aponxi/npm-execxi

ExecXI est une extension de noeud écrite en C++ permettant d'exécuter les commandes Shell une par une, générant le résultat de la commande sur la console en temps réel. Des manières facultatives chaînées et non chaînées sont présentes; ce qui signifie que vous pouvez choisir d'arrêter le script après l'échec d'une commande (chaînée), ou vous pouvez continuer comme si rien ne s'était passé!

Les instructions d'utilisation figurent dans le fichier fichier Lisez-moi . N'hésitez pas à faire des demandes de tirage ou à soumettre des problèmes!

EDIT:  Cependant, il ne retourne pas encore la sortie standard ... Il suffit de les sortir en temps réel.  C'est le cas maintenant Eh bien, je viens de le publier aujourd'hui. Peut-être pourrions-nous en tirer parti.

Quoi qu'il en soit, j'ai pensé qu'il valait la peine de le mentionner.

3
Logan

vous pouvez effectuer des opérations Shell synchrones dans nodejs comme ceci:

var execSync = function(cmd) {

    var exec  = require('child_process').exec;
    var fs = require('fs');

    //for linux use ; instead of &&
    //execute your command followed by a simple echo 
    //to file to indicate process is finished
    exec(cmd + " > c:\\stdout.txt && echo done > c:\\sync.txt");

    while (true) {
        //consider a timeout option to prevent infinite loop
        //NOTE: this will max out your cpu too!
        try {
            var status = fs.readFileSync('c:\\sync.txt', 'utf8');

            if (status.trim() == "done") {
                var res = fs.readFileSync("c:\\stdout.txt", 'utf8');
                fs.unlinkSync("c:\\stdout.txt"); //cleanup temp files
                fs.unlinkSync("c:\\sync.txt");
                return res;
            }
        } catch(e) { } //readFileSync will fail until file exists
    }

};

//won't return anything, but will take 10 seconds to run
console.log(execSync("sleep 10")); 

//assuming there are a lot of files and subdirectories, 
//this too may take a while, use your own applicable file path
console.log(execSync("dir /s c:\\usr\\docs\\"));

EDIT - cet exemple est destiné aux environnements Windows, ajustez-le si nécessaire

1
Marcus Pope

En réalité, j’ai dû exécuter plusieurs commandes l’un après l’autre à partir d’un script de préinstallation package.json d’une manière qui fonctionnerait à la fois sous Windows et sous Linux/OSX. Je ne pouvais donc pas compter sur un module non essentiel.

Alors voici ce que je suis venu avec:

#cmds.coffee
childproc = require 'child_process'

exports.exec = (cmds) ->
  next = ->
    if cmds.length > 0
      cmd = cmds.shift()
      console.log "Running command: #{cmd}"
      childproc.exec cmd, (err, stdout, stderr) ->
        if err? then console.log err
        if stdout? then console.log stdout
        if stderr? then console.log stderr
        next()
    else
      console.log "Done executing commands."

  console.log "Running the follows commands:"
  console.log cmds
  next()

Vous pouvez l'utiliser comme ceci:

require('./cmds').exec ['grunt coffee', 'nodeunit test/tls-config.js']

EDIT: comme indiqué, cela ne retourne pas la sortie et ne vous permet pas d'utiliser le résultat des commandes dans un programme Node. Une autre idée consiste à utiliser des backcalls LiveScript. http://livescript.net/

1
Jason Livesay