Node.js ile bir komut satırı ikili dosyası yürütün


648

Ruby'den Node.js'ye bir CLI kütüphanesi taşıma sürecindeyim. Kodumda gerektiğinde birkaç üçüncü taraf ikili dosyası yürütüyorum. Düğümde bunu en iyi nasıl yapacağımdan emin değilim.

Ruby'de PrinceXML'i bir dosyayı PDF'ye dönüştürmek için çağırdığım bir örnek:

cmd = system("prince -v builds/pdf/book.html -o builds/pdf/book.pdf")

Düğümdeki eşdeğer kod nedir?


3
Bu kütüphane başlamak için iyi bir yer. İşlemleri tüm işletim sistemi platformlarında oluşturmanıza olanak tanır.
Obsidiyen


2
En basit child_process.exec kullanmaktır, işte bazı iyi örnekler
drorw

Yanıtlar:


1069

Node.js'nin (v8.1.4) daha yeni bir sürümü için, etkinlikler ve çağrılar eski sürümlerle benzer veya aynıdır, ancak standart daha yeni dil özelliklerinin kullanılması önerilir. Örnekler:

Arabellek, akışsız biçimlendirilmiş çıktılar (hepsini bir kerede alırsınız) için şunu kullanın child_process.exec:

const { exec } = require('child_process');
exec('cat *.js bad_file | wc -l', (err, stdout, stderr) => {
  if (err) {
    // node couldn't execute the command
    return;
  }

  // the *entire* stdout and stderr (buffered)
  console.log(`stdout: ${stdout}`);
  console.log(`stderr: ${stderr}`);
});

Promises ile de kullanabilirsiniz:

const util = require('util');
const exec = util.promisify(require('child_process').exec);

async function ls() {
  const { stdout, stderr } = await exec('ls');
  console.log('stdout:', stdout);
  console.log('stderr:', stderr);
}
ls();

Verileri yavaş yavaş parçalar halinde (akış olarak çıktı) almak istiyorsanız, şunu kullanın child_process.spawn:

const { spawn } = require('child_process');
const child = spawn('ls', ['-lh', '/usr']);

// use child.stdout.setEncoding('utf8'); if you want text chunks
child.stdout.on('data', (chunk) => {
  // data from standard output is here as buffers
});

// since these are streams, you can pipe them elsewhere
child.stderr.pipe(dest);

child.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

Bu işlevlerin her ikisinin de senkron bir karşılığı vardır. Bunun için bir örnek child_process.execSync:

const { execSync } = require('child_process');
// stderr is sent to stderr of parent process
// you can set options.stdio if you want it to go elsewhere
let stdout = execSync('ls');

Yanı sıra child_process.spawnSync:

const { spawnSync} = require('child_process');
const child = spawnSync('ls', ['-lh', '/usr']);

console.log('error', child.error);
console.log('stdout ', child.stdout);
console.log('stderr ', child.stderr);

Not: Aşağıdaki kod hala işlevseldir, ancak öncelikle ES5 ve önceki kullanıcıları hedeflemektedir.

Node.js ile alt süreçleri yumurtlama modülü belgelerinde (v5.0.0) iyi belgelenmiştir . Bir komutu yürütmek ve çıktısını arabellek olarak almak için şunu kullanın child_process.exec:

var exec = require('child_process').exec;
var cmd = 'prince -v builds/pdf/book.html -o builds/pdf/book.pdf';

exec(cmd, function(error, stdout, stderr) {
  // command output is in stdout
});

Büyük miktarda çıktı beklerken olduğu gibi akışla tanıtıcı işlem G / Ç kullanmanız gerekiyorsa, şunları kullanın child_process.spawn:

var spawn = require('child_process').spawn;
var child = spawn('prince', [
  '-v', 'builds/pdf/book.html',
  '-o', 'builds/pdf/book.pdf'
]);

child.stdout.on('data', function(chunk) {
  // output will be here in chunks
});

// or if you want to send output elsewhere
child.stdout.pipe(dest);

Komut yerine bir dosya yürütüyorsanız child_process.execFile, hangi parametrelerle hemen hemen aynı olan spawnancak execçıktı arabellekleri almak gibi dördüncü bir geri arama parametresine sahip olan parametreleri kullanmak isteyebilirsiniz . Bu biraz şöyle görünebilir:

var execFile = require('child_process').execFile;
execFile(file, args, options, function(error, stdout, stderr) {
  // command output is in stdout
});

V0.11.12 itibariyle , Düğüm artık eşzamanlı spawnve exec. Yukarıda açıklanan yöntemlerin tümü eşzamansızdır ve eşzamanlı bir karşılığı vardır. Onlar için belgeleri burada bulabilirsiniz . Komut dosyaları için yararlı olsalar da, alt işlemleri eşzamansız olarak oluşturmak için kullanılan yöntemlerin aksine, eşzamanlı yöntemlerin bir örneğini döndürmediğini unutmayın ChildProcess.


19
TEŞEKKÜR EDERİM. Bu beni deli ediyordu. Bazen, bariz çözümün işaret edilmesine yardımcı olur, böylece noobs (düğüme) öğrenebilir ve onunla çalışabiliriz.
Dave Thompson

10
Not: requir ('child_process'). ExecFile (), burada prens gibi sistem çapında bilinen bir komut yerine bir dosyayı çalıştırması gereken insanlar için ilgi çekici olacaktır.
Louis Ameline

2
Yerine child.pipe(dest)(yok olan), kullanmak zorunda child.stdout.pipe(dest)ve child.stderr.pipe(dest), örneğin child.stdout.pipe(process.stdout)ve child.stderr.pipe(process.stderr).
ComFreek

Her şeyi bir dosyaya koymak istemiyorsam, ancak birden fazla komut yürütmek istersem ne olur? Belki echo "hello"ve gibi echo "world".
Cameron

Bunu yapmanın standart yolu bu mu? nasıl tüm sarmalayıcı nodejs yazılır? yani komut çalıştırmak için gerekir gearman, rabbitmq vb diyelim ama onlar da bazı sarıcı var ama kendi kütüphane kodunda bu kodu bulamıyorum
ANinJa

261

JS Düğümü v13.9.0, LTS v12.16.1ve v10.19.0 --- Mar 2020

Async yöntemi (Unix):

'use strict';

const { spawn } = require( 'child_process' );
const ls = spawn( 'ls', [ '-lh', '/usr' ] );

ls.stdout.on( 'data', data => {
    console.log( `stdout: ${data}` );
} );

ls.stderr.on( 'data', data => {
    console.log( `stderr: ${data}` );
} );

ls.on( 'close', code => {
    console.log( `child process exited with code ${code}` );
} );


Async yöntemi (Windows):

'use strict';

const { spawn } = require( 'child_process' );
const dir = spawn('cmd', ['/c', 'dir'])

dir.stdout.on( 'data', data => console.log( `stdout: ${data}` ) );
dir.stderr.on( 'data', data => console.log( `stderr: ${data}` ) );
dir.on( 'close', code => console.log( `child process exited with code ${code}` ) );


Senkronizasyon:

'use strict';

const { spawnSync } = require( 'child_process' );
const ls = spawnSync( 'ls', [ '-lh', '/usr' ] );

console.log( `stderr: ${ls.stderr.toString()}` );
console.log( `stdout: ${ls.stdout.toString()}` );

Gönderen node.js v13.9.0 Belgeler

Aynı şey Node.js v12.16.1 Belgeleri ve Node.js v10.19.0 Belgeleri için de geçerlidir.


8
Hem uygun hem de basit sürümleri verdiğiniz için teşekkür ederiz. Biraz daha basit senkronizasyon sürümü benim bir kapalı "bir şey yapmak ve atmak" komut dosyası için tamamen iyiydi.
Brian Jorden

Sorun değil! Bazılarına göre "uygun" olmasa bile her ikisi de olması her zaman güzel.
iSkore

7
Bu örneği Windows'da yapabilmek için kullanmak gerektiğini belirtmek gerekir 'cmd', ['/c', 'dir']. En azından ben 'dir'bunu hatırlamadan önce neden argümanlar olmadan çalışmıyor yüksek ve düşük arıyorlardı ...;)
AndyO

1
Bunların hiçbiri konsola HERHANGİ BİR çıkış vermez.
Tyguy7

@ Tyguy7 nasıl çalıştırıyorsunuz? Konsol nesnesinde herhangi bir geçersiz kılma var mı?
iSkore

73

Child_process.exec arıyorsunuz

İşte örnek:

const exec = require('child_process').exec;
const child = exec('cat *.js bad_file | wc -l',
    (error, stdout, stderr) => {
        console.log(`stdout: ${stdout}`);
        console.log(`stderr: ${stderr}`);
        if (error !== null) {
            console.log(`exec error: ${error}`);
        }
});

Doğru. Ancak, bu tür bir çocuk süreci çağırmanın, stdout uzunluğu için sınırlamaları olduğunu unutmayın.
hgoebl

@hgoebl, o zaman alternatif nedir?
Harshdeep

2
@ Uzun stdout çıkışları durumunda (örneğin birkaç MB) stdout'ta dataolayları dinleyebilirsiniz . Dokümanlara bak, ama böyle bir şey olmalı childProc.stdout.on("data", fn).
hgoebl

30
const exec = require("child_process").exec
exec("ls", (error, stdout, stderr) => {
 //do whatever here
})

14
Lütfen bu kodun nasıl çalıştığı ve cevabı nasıl çözdüğü hakkında daha fazla açıklama ekleyin. StackOverflow'un gelecekte bunu okuyan insanlar için bir cevap arşivi oluşturduğunu unutmayın.
Al Sweigart

4
Al'ın söylediği doğrudur, ancak bu cevabın yararı, hızlı bir cevaba ihtiyaç duyan biri için en iyi cevabı okumak zorunda olmasından çok daha basit olduğunu söyleyeceğim.

29

Sürüm 4 olduğundan en yakın alternatif child_process.execSyncyöntemdir:

const {execSync} = require('child_process');

let output = execSync('prince -v builds/pdf/book.html -o builds/pdf/book.pdf');

execSyncÇağrı olay döngüsünü engellediğini unutmayın .


Bu son düğümde harika çalışıyor. Yine de bir child_processvarlık yaratılıyor execSyncmu? Ve komuttan hemen sonra kaldırılıyor, değil mi? Hafıza sızıntısı yok mu?
NiCk Newman

1
Evet, bellek sızıntısı yok. Sanırım düğümde hiç yaratmadan sadece libuv alt süreç yapılarını başlatır.
Paul Rumkin

21

Üst cevaba çok benzeyen ama aynı zamanda senkronize bir şey istiyorsanız , bu işe yarayacaktır.

var execSync = require('child_process').execSync;
var cmd = "echo 'hello world'";

var options = {
  encoding: 'utf8'
};

console.log(execSync(cmd, options));

14

Ben sadece kolayca Unix / windows ile başa çıkmak için bir Cli yardımcı yazdı.

JavaScript:

define(["require", "exports"], function (require, exports) {
    /**
     * Helper to use the Command Line Interface (CLI) easily with both Windows and Unix environments.
     * Requires underscore or lodash as global through "_".
     */
    var Cli = (function () {
        function Cli() {}
            /**
             * Execute a CLI command.
             * Manage Windows and Unix environment and try to execute the command on both env if fails.
             * Order: Windows -> Unix.
             *
             * @param command                   Command to execute. ('grunt')
             * @param args                      Args of the command. ('watch')
             * @param callback                  Success.
             * @param callbackErrorWindows      Failure on Windows env.
             * @param callbackErrorUnix         Failure on Unix env.
             */
        Cli.execute = function (command, args, callback, callbackErrorWindows, callbackErrorUnix) {
            if (typeof args === "undefined") {
                args = [];
            }
            Cli.windows(command, args, callback, function () {
                callbackErrorWindows();

                try {
                    Cli.unix(command, args, callback, callbackErrorUnix);
                } catch (e) {
                    console.log('------------- Failed to perform the command: "' + command + '" on all environments. -------------');
                }
            });
        };

        /**
         * Execute a command on Windows environment.
         *
         * @param command       Command to execute. ('grunt')
         * @param args          Args of the command. ('watch')
         * @param callback      Success callback.
         * @param callbackError Failure callback.
         */
        Cli.windows = function (command, args, callback, callbackError) {
            if (typeof args === "undefined") {
                args = [];
            }
            try {
                Cli._execute(process.env.comspec, _.union(['/c', command], args));
                callback(command, args, 'Windows');
            } catch (e) {
                callbackError(command, args, 'Windows');
            }
        };

        /**
         * Execute a command on Unix environment.
         *
         * @param command       Command to execute. ('grunt')
         * @param args          Args of the command. ('watch')
         * @param callback      Success callback.
         * @param callbackError Failure callback.
         */
        Cli.unix = function (command, args, callback, callbackError) {
            if (typeof args === "undefined") {
                args = [];
            }
            try {
                Cli._execute(command, args);
                callback(command, args, 'Unix');
            } catch (e) {
                callbackError(command, args, 'Unix');
            }
        };

        /**
         * Execute a command no matters what's the environment.
         *
         * @param command   Command to execute. ('grunt')
         * @param args      Args of the command. ('watch')
         * @private
         */
        Cli._execute = function (command, args) {
            var spawn = require('child_process').spawn;
            var childProcess = spawn(command, args);

            childProcess.stdout.on("data", function (data) {
                console.log(data.toString());
            });

            childProcess.stderr.on("data", function (data) {
                console.error(data.toString());
            });
        };
        return Cli;
    })();
    exports.Cli = Cli;
});

Patlama orijinal kaynak dosyası:

 /**
 * Helper to use the Command Line Interface (CLI) easily with both Windows and Unix environments.
 * Requires underscore or lodash as global through "_".
 */
export class Cli {

    /**
     * Execute a CLI command.
     * Manage Windows and Unix environment and try to execute the command on both env if fails.
     * Order: Windows -> Unix.
     *
     * @param command                   Command to execute. ('grunt')
     * @param args                      Args of the command. ('watch')
     * @param callback                  Success.
     * @param callbackErrorWindows      Failure on Windows env.
     * @param callbackErrorUnix         Failure on Unix env.
     */
    public static execute(command: string, args: string[] = [], callback ? : any, callbackErrorWindows ? : any, callbackErrorUnix ? : any) {
        Cli.windows(command, args, callback, function () {
            callbackErrorWindows();

            try {
                Cli.unix(command, args, callback, callbackErrorUnix);
            } catch (e) {
                console.log('------------- Failed to perform the command: "' + command + '" on all environments. -------------');
            }
        });
    }

    /**
     * Execute a command on Windows environment.
     *
     * @param command       Command to execute. ('grunt')
     * @param args          Args of the command. ('watch')
     * @param callback      Success callback.
     * @param callbackError Failure callback.
     */
    public static windows(command: string, args: string[] = [], callback ? : any, callbackError ? : any) {
        try {
            Cli._execute(process.env.comspec, _.union(['/c', command], args));
            callback(command, args, 'Windows');
        } catch (e) {
            callbackError(command, args, 'Windows');
        }
    }

    /**
     * Execute a command on Unix environment.
     *
     * @param command       Command to execute. ('grunt')
     * @param args          Args of the command. ('watch')
     * @param callback      Success callback.
     * @param callbackError Failure callback.
     */
    public static unix(command: string, args: string[] = [], callback ? : any, callbackError ? : any) {
        try {
            Cli._execute(command, args);
            callback(command, args, 'Unix');
        } catch (e) {
            callbackError(command, args, 'Unix');
        }
    }

    /**
     * Execute a command no matters what's the environment.
     *
     * @param command   Command to execute. ('grunt')
     * @param args      Args of the command. ('watch')
     * @private
     */
    private static _execute(command, args) {
        var spawn = require('child_process').spawn;
        var childProcess = spawn(command, args);

        childProcess.stdout.on("data", function (data) {
            console.log(data.toString());
        });

        childProcess.stderr.on("data", function (data) {
            console.error(data.toString());
        });
    }
}

Example of use:

    Cli.execute(Grunt._command, args, function (command, args, env) {
        console.log('Grunt has been automatically executed. (' + env + ')');

    }, function (command, args, env) {
        console.error('------------- Windows "' + command + '" command failed, trying Unix... ---------------');

    }, function (command, args, env) {
        console.error('------------- Unix "' + command + '" command failed too. ---------------');
    });

1
Buradaki en son sürüm, CLI'de
Vadorequest

7

Şimdi shelljs'i (v4 düğümünden) aşağıdaki gibi kullanabilirsiniz:

var shell = require('shelljs');

shell.echo('hello world');
shell.exec('node --version')

6

Bir bağımlılık sakıncası yoksa ve vaatler kullanmak istiyorsanız, child-process-promiseçalışır:

Kurulum

npm install child-process-promise --save

exec Kullanım

var exec = require('child-process-promise').exec;

exec('echo hello')
    .then(function (result) {
        var stdout = result.stdout;
        var stderr = result.stderr;
        console.log('stdout: ', stdout);
        console.log('stderr: ', stderr);
    })
    .catch(function (err) {
        console.error('ERROR: ', err);
    });

spawn kullanımı

var spawn = require('child-process-promise').spawn;

var promise = spawn('echo', ['hello']);

var childProcess = promise.childProcess;

console.log('[spawn] childProcess.pid: ', childProcess.pid);
childProcess.stdout.on('data', function (data) {
    console.log('[spawn] stdout: ', data.toString());
});
childProcess.stderr.on('data', function (data) {
    console.log('[spawn] stderr: ', data.toString());
});

promise.then(function () {
        console.log('[spawn] done!');
    })
    .catch(function (err) {
        console.error('[spawn] ERROR: ', err);
    });

4

Bu hafif npmpaketi kullanın :system-commands

Buraya bak .

Bu şekilde içe aktarın:

const system = require('system-commands')

Bunun gibi komutları çalıştırın:

system('ls').then(output => {
    console.log(output)
}).catch(error => {
    console.error(error)
})

Mükemmel! Benim ihtiyaçları için harika çalışıyor.
roosevelt

3

@ hexacyanide'in cevabı neredeyse tamdır. Windows'ta komut princeolabilir prince.exe, prince.cmd, prince.batya da sadece prince(I taşlar birlikte nasıl hiçbir farkındayım ama npm kutuları bir sh yazısı ve bir toplu komut ile gelen - npmvenpm.cmd ). Unix ve Windows üzerinde çalışacak taşınabilir bir komut dosyası yazmak istiyorsanız, doğru yürütülebilir dosyayı oluşturmanız gerekir.

İşte basit ama taşınabilir bir spawn işlevi:

function spawn(cmd, args, opt) {
    var isWindows = /win/.test(process.platform);

    if ( isWindows ) {
        if ( !args ) args = [];
        args.unshift(cmd);
        args.unshift('/c');
        cmd = process.env.comspec;
    }

    return child_process.spawn(cmd, args, opt);
}

var cmd = spawn("prince", ["-v", "builds/pdf/book.html", "-o", "builds/pdf/book.pdf"])

// Use these props to get execution results:
// cmd.stdin;
// cmd.stdout;
// cmd.stderr;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.