child_process.spawn în Node.js

Sistem, procese și fire Node.js 0.1.90; spawnSync din 0.12

Pornește un program ca proces copil și citește ieșirea lui pe măsură ce apare (stream), fără shell.

Sintaxă
import { spawn, spawnSync } from "node:child_process";
const copil = spawn(comanda, [argumente], [opțiuni]);
copil.stdout.on("data", ...); copil.on("close", (cod) => ...);

Ce face child_process.spawn

spawn pornește direct un program, cu argumentele date ca tablou, fără shell. Spre deosebire de exec, nu așteaptă finalul: copil.stdout și copil.stderr sunt stream-uri din care citești bucăți pe măsură ce programul afișează. Este varianta potrivită pentru comenzi lungi (compilări, descărcări) sau cu multă ieșire.

Procesul copil emite evenimentul "close" cu codul de ieșire, iar "error" dacă programul nu a putut fi pornit (de exemplu nu există). Poți scrie în copil.stdin, ca și cum utilizatorul ar tasta.

Opțiunea stdio: "inherit" leagă ieșirea copilului direct de terminalul tău (vezi culorile și progresul ca la rularea manuală). spawnSync este varianta sincronă și întoarce un obiect cu status, stdout, stderr. Pentru a porni tot Node.js, folosește process.execPath (calea executabilului curent) în loc de "node".

Parametri

Parametru Descriere
comanda Programul de pornit ("git", process.execPath).
argumente Tablou de șiruri, trimise exact, fără interpretare de shell.
opțiuni.stdio "pipe" (implicit), "inherit" sau "ignore".
opțiuni.cwd / env Directorul de lucru și variabilele de mediu ale copilului.
opțiuni.shell true rulează prin shell (evită dacă argumentele vin din afară).

Ce returnează

Un obiect ChildProcess (spawnSync: { status, stdout, stderr, ... }).

Exemple

Exemplul 1: Citire pe măsură ce apare ieșirea

Copilul este tot un script Node.js care afișează trei rânduri cu pauză. Părintele le primește pe rând.

import { spawn } from "node:child_process";

const script = `
  for (const oras of ["Iași", "Cluj", "Arad"]) {
    console.log("procesez " + oras);
    await new Promise((r) => setTimeout(r, 20));
  }
  process.exitCode = 3;
`;

const copil = spawn(process.execPath, ["--input-type=module", "-e", script]);
copil.stdout.setEncoding("utf8");
copil.stdout.on("data", (bucata) => process.stdout.write("[copil] " + bucata));
copil.on("close", (cod) => console.log("Copilul a ieșit cu codul", cod));

Rezultat

[copil] procesez Iași
[copil] procesez Cluj
[copil] procesez Arad
Copilul a ieșit cu codul 3

Exemplul 2: Trimitere date pe stdin

import { spawn } from "node:child_process";

const sortare = spawn("sort", ["-r"]);
let rezultat = "";
sortare.stdout.on("data", (b) => (rezultat += b));
sortare.on("close", () => console.log(rezultat.trim().split("\n")));

sortare.stdin.write("Ana\nMaria\nIon\n");
sortare.stdin.end();

Rezultat

[ 'Maria', 'Ion', 'Ana' ]

Exemplul 3: spawnSync și program inexistent

import { spawnSync, spawn } from "node:child_process";

const r = spawnSync(process.execPath, ["-p", "6 * 7"], { encoding: "utf8" });
console.log(r.status, r.stdout.trim());

spawn("program-care-nu-exista").on("error", (e) => console.log(e.code));

Rezultat

0 42
ENOENT

Greșeli frecvente

  • Dai toată comanda ca un singur șir: spawn("git log --oneline") caută un program numit exact așa. Separă: spawn("git", ["log", "--oneline"]).
  • Nu asculți evenimentul "error": dacă programul nu există, eroarea neprinsă oprește tot procesul părinte.
  • Citești stdout doar la "exit": stream-urile pot avea încă date. Folosește "close", care vine după ce s-au închis stream-urile.

Comenzi înrudite

  • child_process.exec: Rulează o comandă în shell (ca în terminal) și primește la final tot textul afișat de ea.
  • child_process.execFile: Rulează direct un program cu argumente separate, fără shell, și primește ieșirea la final. Varianta sigură a lui exec.
  • stream.pipeline: Leagă stream-uri în lanț (citire → transformare → scriere), cu tratarea erorilor și închiderea tuturor la final.
  • worker_threads (Worker): Rulează cod JavaScript în fire de execuție separate, ca un calcul greu să nu blocheze restul programului.