child_process.exec în Node.js

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

Rulează o comandă în shell (ca în terminal) și primește la final tot textul afișat de ea.

Sintaxă
import { exec, execSync } from "node:child_process";
exec(comanda, [opțiuni], (eroare, stdout, stderr) => { ... })
execSync(comanda, [opțiuni])

Ce face child_process.exec

exec pornește un shell (/bin/sh pe Linux și macOS, cmd.exe pe Windows) și îi dă comanda ca text. Poți folosi tot ce merge în terminal: pipe-uri (|), redirecționări, &&. Când comanda se termină, primești ieșirea ei completă (stdout și stderr) în funcția de callback.

execSync face același lucru sincron: blochează programul până termină comanda și întoarce ieșirea. Dacă comanda iese cu cod diferit de zero, aruncă o eroare cu proprietățile status, stdout și stderr. Varianta cu promisiuni se obține cu util.promisify(exec), care întoarce { stdout, stderr }.

Ieșirea este ținută în memorie (implicit maxim 1 MB, opțiunea maxBuffer). Pentru comenzi care afișează mult sau rulează mult timp folosește spawn. Și cel mai important: nu pune niciodată în comandă text primit de la utilizator, pentru că shell-ul l-ar interpreta (injectare de comenzi). Pentru argumente variabile folosește execFile.

Parametri

Parametru Descriere
comanda Textul comenzii, exact ca în terminal.
opțiuni.cwd Directorul în care rulează comanda.
opțiuni.env Variabilele de mediu (implicit cele ale procesului).
opțiuni.encoding "utf8" implicit la exec; la execSync fără ea primești un Buffer.
opțiuni.timeout Oprește comanda după atâtea milisecunde.

Ce returnează

exec: obiectul ChildProcess. execSync: ieșirea comenzii.

Exemple

Exemplul 1: Comandă cu pipe, varianta cu promisiuni

import { exec } from "node:child_process";
import { promisify } from "node:util";
import { writeFileSync } from "node:fs";

const execAsync = promisify(exec);
writeFileSync("orase.txt", "Iași\nCluj\nBrașov\nArad\n");

const { stdout } = await execAsync("sort orase.txt | head -n 2");
console.log(stdout.trim().split("\n"));

Rezultat

[ 'Arad', 'Brașov' ]

Exemplul 2: execSync și codul de ieșire

O comandă care eșuează aruncă o eroare. stdio cu "pipe" împiedică mesajul de eroare al comenzii să apară direct în terminal.

import { execSync } from "node:child_process";

const versiune = execSync("node -p process.versions.node", { encoding: "utf8" });
console.log("Node major:", versiune.split(".")[0]);

try {
  execSync("ls fisier-care-nu-exista", { stdio: "pipe" });
} catch (eroare) {
  console.log("Comanda a eșuat cu codul", eroare.status);
}

Rezultat

Node major: 26
Comanda a eșuat cu codul 1

Exemplul 3: Callback cu eroare, stdout și stderr

import { exec } from "node:child_process";

exec("echo Salut din shell && echo atenție 1>&2", (eroare, stdout, stderr) => {
  if (eroare) throw eroare;
  console.log("stdout:", stdout.trim());
  console.log("stderr:", stderr.trim());
});

Rezultat

stdout: Salut din shell
stderr: atenție

Greșeli frecvente

  • Construiești comanda din date primite: exec(`cat ${numeFisier}`). Dacă cineva trimite a.txt; rm -rf ~, shell-ul rulează și a doua comandă. Folosește execFile("cat", [numeFisier]).
  • Rulezi cu exec o comandă care afișează mult (un find mare): peste maxBuffer procesul este oprit cu ERR_CHILD_PROCESS_STDIO_MAXBUFFER. Folosește spawn și citește ieșirea ca stream.
  • Folosești execSync într-un server web: blochează toate cererile cât rulează comanda. Pe server folosește variantele asincrone.

Comenzi înrudite

  • 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.
  • child_process.spawn: Pornește un program ca proces copil și citește ieșirea lui pe măsură ce apare (stream), fără shell.
  • util.promisify: Transformă o funcție cu callback în stil Node.js (eroare, rezultat) într-o funcție care întoarce o promisiune.
  • process.exit / process.exitCode: Stabilește codul de ieșire al scriptului (0 = succes) sau oprește procesul imediat cu process.exit.