Execute a command line binary with Node.js

后端 未结 12 2214
星月不相逢
星月不相逢 2020-11-22 01:39

I am in the process of porting a CLI library from Ruby over to Node.js. In my code I execute several third party binaries when necessary. I am not sure how best to accomplis

相关标签:
12条回答
  • 2020-11-22 01:54

    I just wrote a Cli helper to deal with Unix/windows easily.

    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 original source file:

     /**
     * 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. ---------------');
        });
    
    0 讨论(0)
  • 2020-11-22 01:57

    Now you can use shelljs ( from node v4 ) as follows :

    var shell = require('shelljs');
    
    shell.echo('hello world');
    shell.exec('node --version')
    
    0 讨论(0)
  • 2020-11-22 01:59

    Since version 4 the closest alternative is child_process.execSync method:

    const {execSync} = require('child_process');
    
    let output = execSync('prince -v builds/pdf/book.html -o builds/pdf/book.pdf');
    

    ⚠️ Note that execSync call blocks event loop.

    0 讨论(0)
  • 2020-11-22 02:04
    const exec = require("child_process").exec
    exec("ls", (error, stdout, stderr) => {
     //do whatever here
    })
    
    0 讨论(0)
  • 2020-11-22 02:04

    You can use execa.

    For example, as a promise:

    const execa = require('execa')
    
    execa('cat *.js bad_file').then(
      (childProcessResult) => {
        //onFulfilled
        console.log('Success!', childProcessResult)
      },
      (childProcessResult) => {
        //onRejected
        console.log('Error!', childProcessResult)
      }
    )
    

    Execa improves child_process methods with:

    • Promise interface.
    • Strips the final newline from the output so you don't have to do stdout.trim().
    • Supports shebang binaries cross-platform.
    • Improved Windows support.
    • Higher max buffer. 100 MB instead of 200 KB.
    • Executes locally installed binaries by name.
    • Cleans up spawned processes when the parent process dies.
    • Get interleaved output from stdout and stderr similar to what is printed on the terminal. (Async only)
    • Can specify file and arguments as a single string without a shell
    • More descriptive errors.
    0 讨论(0)
  • 2020-11-22 02:06

    Node JS v13.9.0, LTS v12.16.1, and v10.19.0 --- Mar 2020

    Async method (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 method (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}` ) );
    


    Sync:

    '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()}` );
    

    From Node.js v13.9.0 Documentation

    The same goes for Node.js v12.16.1 Documentation and Node.js v10.19.0 Documentation

    0 讨论(0)
提交回复
热议问题