Ejecuci贸n de comandos de shell con Node.js

    Introducci贸n

    Los administradores y desarrolladores de sistemas recurren con frecuencia a la automatizaci贸n para reducir su carga de trabajo y mejorar sus procesos. Cuando se trabaja con servidores, las tareas automatizadas se suelen programar con scripts de shell. Sin embargo, un desarrollador puede preferir usar un lenguaje de nivel superior m谩s general para tareas complejas. Muchas aplicaciones tambi茅n necesitan interactuar con el sistema de archivos y otros componentes de nivel de sistema operativo, lo que a menudo se hace m谩s f谩cilmente con utilidades de nivel de l铆nea de comando.

    Con Node.js, podemos ejecutar comandos de shell y procesar sus entradas y salidas usando JavaScript. Por lo tanto, podemos escribir la mayor铆a de estas operaciones complejas en JavaScript en lugar del lenguaje de scripts de shell, lo que potencialmente hace que el programa sea m谩s f谩cil de mantener.

    En este art铆culo, aprenderemos las diversas formas de ejecutar comandos de shell en Node.js usando el child_process m贸dulo.

    El m贸dulo child_proccess

    Node.js ejecuta su ciclo de eventos principal en un solo hilo. Sin embargo, eso no significa que todo su procesamiento se realice en ese 煤nico hilo. Las tareas asincr贸nicas en Node.js se ejecutan en otros hilos internos. Cuando est谩n completos, el c贸digo de la devoluci贸n de llamada, o el error, se devuelve al hilo principal 煤nico.

    Estos distintos subprocesos se ejecutan en el mismo proceso de Node.js. Sin embargo, a veces es deseable crear otro proceso para ejecutar c贸digo. Cuando se crea un nuevo proceso, el sistema operativo determina qu茅 procesador utiliza y c贸mo programar sus tareas.

    los child_process El m贸dulo crea nuevos procesos secundarios de nuestro proceso principal de Node.js. Podemos ejecutar comandos de shell con estos procesos secundarios.

    El uso de procesos externos puede mejorar el rendimiento de su aplicaci贸n si se usa correctamente. Por ejemplo, si una funci贸n de una aplicaci贸n Node.js consume mucha CPU, como Node.js es de un solo subproceso, bloquear铆a la ejecuci贸n de las otras tareas mientras se ejecuta.

    Sin embargo, podemos delegar ese c贸digo intensivo en recursos a un proceso hijo, digamos un programa C ++ muy eficiente. Nuestro c贸digo Node.js ejecutar谩 ese programa C ++ en un nuevo proceso, sin bloquear sus otras actividades, y cuando se complete, procesar谩 su salida.

    Dos funciones que usaremos para ejecutar comandos de shell son exec y spawn.

    La funci贸n ejecutiva

    los exec() La funci贸n crea un nuevo shell y ejecuta un comando dado. La salida de la ejecuci贸n se almacena en b煤fer, lo que significa que se mantiene en la memoria y est谩 disponible para su uso en una devoluci贸n de llamada.

    Usemos exec() funci贸n para listar todas las carpetas y archivos en nuestro directorio actual. En un nuevo archivo Node.js llamado lsExec.js, escribe el siguiente c贸digo:

    const { exec } = require("child_process");
    
    exec("ls -la", (error, stdout, stderr) => {
        if (error) {
            console.log(`error: ${error.message}`);
            return;
        }
        if (stderr) {
            console.log(`stderr: ${stderr}`);
            return;
        }
        console.log(`stdout: ${stdout}`);
    });
    

    Primero, requerimos el child_process m贸dulo en nuestro programa, espec铆ficamente utilizando el exec() funci贸n (a trav茅s de la desestructuraci贸n ES6). A continuaci贸n, llamamos al exec() funci贸n con dos par谩metros:

    • Una cadena con el comando de shell que queremos ejecutar.
    • Una funci贸n de devoluci贸n de llamada con tres par谩metros: error, stdout, stderr.

    El comando de shell que estamos ejecutando es ls -la, que deber铆a enumerar todos los archivos y carpetas en nuestro directorio actual l铆nea por l铆nea, incluidos los archivos / carpetas ocultos. La funci贸n de devoluci贸n de llamada registra si obtuvimos un error al intentar ejecutar el comando o la salida en el shell stdout o stderr arroyos.

    Nota la error el objeto es diferente de stderr. los error el objeto no es nulo cuando el child_process m贸dulo no puede ejecutar un comando. Esto podr铆a suceder si intenta ejecutar otro script de Node.js en exec() pero no se pudo encontrar el archivo, por ejemplo. Por otro lado, si el comando se ejecuta con 茅xito y escribe un mensaje en el flujo de error est谩ndar, entonces el stderr el objeto no ser铆a nulo.

    Si ejecuta ese archivo Node.js, deber铆a ver un resultado similar a:

    $ node lsExec.js
    stdout: total 0
    [email聽protected] 9 arpan arpan  0 Dec  7 00:14 .
    [email聽protected] 4 arpan arpan  0 Dec  7 22:09 ..
    [email聽protected] 1 arpan arpan  0 Dec  7 15:10 lsExec.js
    
    child process exited with code 0
    

    Ahora que hemos entendido c贸mo ejecutar comandos con exec(), aprendamos otra forma de ejecutar comandos con spawn().

    La funci贸n de generaci贸n

    los spawn() La funci贸n ejecuta un comando en un nuevo proceso. Esta funci贸n utiliza una API Stream, por lo que su salida del comando est谩 disponible a trav茅s de oyentes.

    Al igual que antes, usaremos el spawn() funci贸n para listar todas las carpetas y archivos en nuestro directorio actual. Creemos un nuevo archivo Node.js, lsSpawn.jse ingrese lo siguiente:

    const { spawn } = require("child_process");
    
    const ls = spawn("ls", ["-la"]);
    
    ls.stdout.on("data", data => {
        console.log(`stdout: ${data}`);
    });
    
    ls.stderr.on("data", data => {
        console.log(`stderr: ${data}`);
    });
    
    ls.on('error', (error) => {
        console.log(`error: ${error.message}`);
    });
    
    ls.on("close", code => {
        console.log(`child process exited with code ${code}`);
    });
    

    Comenzamos por exigir el spawn() funci贸n de la child_process m贸dulo. Luego, creamos un nuevo proceso que ejecuta el ls comando, pasando -la como argumento. Observe c贸mo los argumentos se mantienen en una matriz y no se incluyen en la cadena de comandos.

    Luego configuramos nuestros oyentes. los stdout objeto de ls, dispara un data evento cuando el comando escribe en esa secuencia. Del mismo modo, el stderr tambi茅n dispara un data evento cuando el comando escribe en esa secuencia.

    Los errores se detectan al escucharlos directamente en el objeto que almacena la referencia del comando. Solo obtendr谩 un error si child_process no ejecuta el comando.

    los close El evento ocurre cuando el comando ha terminado.

    Si ejecutamos este archivo Node.js, deber铆amos obtener la salida como antes con exec():

    $ node lsSpawn.js
    stdout: total 0
    [email聽protected] 9 arpan arpan  0 Dec  7 00:14 .
    [email聽protected] 4 arpan arpan  0 Dec  7 22:09 ..
    [email聽protected] 1 arpan arpan  0 Dec  7 15:10 lsExec.js
    [email聽protected] 1 arpan arpan  0 Dec  7 15:40 lsSpawn.js
    
    child process exited with code 0
    

    驴Cu谩ndo usar exec y spawn?

    La diferencia clave entre exec() y spawn() as铆 es como devuelven los datos. Como exec() almacena toda la salida en un b煤fer, requiere m谩s memoria que spawn(), que transmite la salida como viene.

    Generalmente, si no espera que se devuelvan grandes cantidades de datos, puede usar exec() por simplicidad. Buenos ejemplos de casos de uso son crear una carpeta u obtener el estado de un archivo. Sin embargo, si espera una gran cantidad de resultados de su comando, debe usar spawn(). Un buen ejemplo ser铆a usar el comando para manipular datos binarios y luego cargarlos en su programa Node.js.

    Conclusi贸n

    Node.js puede ejecutar comandos de shell utilizando el est谩ndar child_process m贸dulo. Si usamos el exec() , nuestro comando se ejecutar谩 y su salida estar谩 disponible para nosotros en una devoluci贸n de llamada. Si usamos el spawn() m贸dulo, su salida estar谩 disponible a trav茅s de detectores de eventos.

    Si nuestra aplicaci贸n espera una gran cantidad de resultados de nuestros comandos, deber铆amos preferir spawn() encima exec(). De lo contrario, podr铆amos optar por usar exec() por su sencillez.

    Ahora que puede ejecutar tareas externas a Node.js, 驴qu茅 aplicaciones crear铆a?

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *