Ich bin dabei, eine CLI-Bibliothek von Ruby auf Node.js zu portieren. In meinem Code führe ich bei Bedarf mehrere Drittanbieter-Binärdateien aus. Ich bin nicht sicher, wie ich dies am besten in Node erreichen kann.
Hier ein Beispiel in Ruby, in dem ich PrinceXML anrufe, um eine Datei in eine PDF-Datei zu konvertieren:
cmd = system("prince -v builds/pdf/book.html -o builds/pdf/book.pdf")
Was ist der äquivalente Code in Node?
Für eine noch neuere Version von Node.js (v8.1.4) sind die Ereignisse und Aufrufe ähnlich oder identisch mit älteren Versionen. Es wird jedoch empfohlen, die Standardfunktionen für neuere Sprachen zu verwenden. Beispiele:
Für gepufferte, nicht im Stream formatierte Ausgaben (Sie erhalten alles auf einmal), verwenden Sie 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}`);
});
Sie können es auch mit Versprechungen verwenden:
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();
Wenn Sie die Daten schrittweise in Stücken erhalten möchten (Ausgabe als Stream), verwenden Sie 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}`);
});
Beide Funktionen haben ein synchrones Gegenstück. Ein Beispiel für 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');
Sowie 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);
Hinweis: Der folgende Code ist noch funktionsfähig, richtet sich jedoch in erster Linie an Benutzer von ES5 und davor.
Das Modul zum Erzeugen von untergeordneten Prozessen mit Node.js ist in der Dokumentation (v5.0.0) gut dokumentiert. Um einen Befehl auszuführen und seine gesamte Ausgabe als Puffer abzurufen, verwenden Sie 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
});
Wenn Sie die Prozess-E/A für die Verarbeitung mit Streams verwenden müssen, z. B. wenn Sie große Ausgabenmengen erwarten, verwenden Sie 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);
Wenn Sie eine Datei anstelle eines Befehls ausführen, möchten Sie möglicherweise child_process.execFile
verwenden. Diese Parameter sind nahezu identisch mit spawn
, verfügen jedoch über einen vierten Callback-Parameter wie exec
zum Abrufen von Ausgabepuffern. Das könnte ein bisschen so aussehen:
var execFile = require('child_process').execFile;
execFile(file, args, options, function(error, stdout, stderr) {
// command output is in stdout
});
Seit v0.11.12 unterstützt Node jetzt synchrone spawn
und exec
. Alle oben beschriebenen Methoden sind asynchron und haben ein synchrones Gegenstück. Dokumentation für sie finden Sie hier . Beachten Sie, dass diese synchronen Methoden im Gegensatz zu den Methoden, die zum asynchronen Erzeugen untergeordneter Prozesse verwendet werden, keine Instanz von ChildProcess
zurückgeben.
v11.5.0
, LTS v10.14.2
und v8.14.1
--- Dezember 2018Async und richtige Methode (Unix):
'use strict';
const
{ spawn } = require( 'child_process' ),
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-Methode (Windows):
'use strict';
const
{ spawn } = require( 'child_process' ),
dir = spawn( '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}` ) );
Sync:
'use strict';
const
{ spawnSync } = require( 'child_process' ),
ls = spawnSync( 'ls', [ '-lh', '/usr' ] );
console.log( `stderr: ${ls.stderr.toString()}` );
console.log( `stdout: ${ls.stdout.toString()}` );
Aus Node.js v11.5.0 Dokumentation
Dasselbe gilt für Node.js v10.14.2 Dokumentation und Node.js v8.14.1 Dokumentation
Sie suchen nach child_process.exec
Hier ist das Beispiel:
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}`);
}
});
const exec = require("child_process").exec
exec("ls", (error, stdout, stderr) => {
//do whatever here
})
Wenn Sie etwas wünschen, das der Top-Antwort sehr ähnlich ist, aber auch synchron ist, funktioniert dies.
var execSync = require('child_process').execSync;
var cmd = "echo 'hello world'";
var options = {
encoding: 'utf8'
};
console.log(execSync(cmd, options));
Ich habe gerade einen Cli-Helfer geschrieben, um mit Unix/Windows problemlos umzugehen.
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;
});
TypeScript-Originalquelldatei:
/**
* 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. ---------------');
});
Seit Version 4 ist die nächstliegende Alternative die child_process.execSync
-Methode:
const execSync = require('child_process').execSync;
let cmd = execSync('prince -v builds/pdf/book.html -o builds/pdf/book.pdf');
Beachten Sie, dass diese Methode die Ereignisschleife blockiert.
Wenn Sie keine Abhängigkeit von einer Abhängigkeit haben und Versprechen verwenden möchten, funktioniert child-process-promise
:
installation
npm install child-process-promise --save
exec Verwendung
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-Nutzung
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);
});
Die Antwort von @hexacyanide ist fast vollständig. Unter Windows-Befehl könnte prince
prince.exe
, prince.cmd
, prince.bat
oder einfach prince
sein (ich weiß nicht, wie Edelsteine gebündelt werden, aber npm-Bins enthalten ein Sh-Skript und ein Batch-Skript - npm
und npm.cmd
) . Wenn Sie ein portables Skript schreiben möchten, das unter Unix und Windows ausgeführt werden kann, müssen Sie die richtige ausführbare Datei erstellen.
Hier ist eine einfache, aber tragbare Spawn-Funktion:
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;
Jetzt können Sie shelljs (von Knoten v4) wie folgt verwenden:
var Shell = require('shelljs');
Shell.echo('hello world');
Shell.exec('node --version')