Выполнение бинарного файла командной строки с помощью Node.js
Я занимаюсь переносом библиотеки командной строки с Ruby на Node.js. В своем коде я выполняю несколько сторонних бинарных файлов при необходимости. Не уверен, каким образом лучше всего это реализовать в Node.js.
Вот пример на Ruby, где я вызываю PrinceXML для конвертации файла в PDF:
cmd = system("prince -v builds/pdf/book.html -o builds/pdf/book.pdf")
Какой эквивалентный код будет на Node.js?
4 ответ(ов)
Теперь вы можете использовать shelljs (начиная с node v4) следующим образом:
var shell = require('shelljs');
shell.echo('hello world');
shell.exec('node --version');
Установите shelljs с помощью команды:
npm install shelljs
Подробности можно найти на странице проекта: https://github.com/shelljs/shelljs.
Перевожу ваш вопрос на русский с учетом стиля ответов на StackOverflow:
Я только что написал вспомогательный класс для командной строки (CLI), который упрощает работу с Unix и Windows.
Вот пример реализации на JavaScript:
define(["require", "exports"], function (require, exports) {
// Вспомогательный класс для удобного использования CLI в окружениях Windows и Unix.
// Требуется библиотека underscore или lodash в глобальной области как "_".
var Cli = (function () {
function Cli() {}
// Выполняет команду CLI, пробуя сначала в Windows, затем в Unix, если в первом случае не удалось.
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('------------- Не удалось выполнить команду: "' + command + '" в обоих окружениях. -------------');
}
});
};
// Выполняет команду в окружении Windows.
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');
}
};
// Выполняет команду в окружении Unix.
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');
}
};
// Выполняет команду, независимо от окружения.
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:
export class Cli {
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('------------- Не удалось выполнить команду: "' + command + '" в обоих окружениях. -------------');
}
});
}
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');
}
}
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');
}
}
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());
});
}
}
Пример использования:
Cli.execute(Grunt._command, args, function (command, args, env) {
console.log('Grunt успешно выполнен автоматически. (' + env + ')');
}, function (command, args, env) {
console.error('------------- Выполнение команды Windows "' + command + '" не удалось, пробуем в Unix... ---------------');
}, function (command, args, env) {
console.error('------------- Выполнение команды Unix "' + command + '" также не удалось. ---------------');
});
Если у вас есть вопросы по коду или по его использованию, не стесняйтесь спрашивать!
Ответ @hexacyanide почти полный. На Windows команда prince
может быть представлена как prince.exe
, prince.cmd
, prince.bat
или просто prince
. Я не знаю, как упаковываются гемы, но npm-бинары идут с sh-скриптом и батч-скриптом - это npm
и npm.cmd
.
Если вы хотите написать переносимый скрипт, который будет работать как в Unix, так и в Windows, вам необходимо запустить правильный исполняемый файл.
Вот простая, но переносимая функция для запуска команд:
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"])
// Используйте эти свойства для получения результатов выполнения:
// cmd.stdin;
// cmd.stdout;
// cmd.stderr;
Эта функция проверяет, запущен ли скрипт в Windows, и в зависимости от этого корректирует команду и аргументы для её выполнения.
Чтобы выполнить команду системы, такую как ls
, в Node.js версии 16, вы можете использовать встроенный модуль child_process
. Вот пример кода, который демонстрирует, как это сделать:
const { execSync } = require('child_process');
try {
const output = execSync('ls'); // ваша системная команда
console.log(output.toString()); // вывод результата на консоль
} catch (error) {
console.error(`Ошибка выполнения команды: ${error.message}`);
}
В этом коде мы используем функцию execSync
, которая выполняет команду синхронно. Результат выполнения команды будет сохранён в переменной output
. Мы также оборачиваем вызов в try...catch
, чтобы обработать любые ошибки, которые могут возникнуть во время выполнения команды. Не забудьте, что выполнение системных команд может быть опасным, особенно если команды формируются на основе пользовательского ввода.
Использование async/await с циклом forEach
Как в Node.js "подключить" функции из других файлов?
Как получить полный объект в console.log() Node.js, а не '[Object]'?
Как прочитать JSON-файл в память сервера?
Обнаружена ошибка: Невозможное нарушение: Неверный тип элемента: ожидался строковый тип (для встроенных компонентов) или класс/функция, но получен объект