exec.Command în Go

Pregătește rularea unui program extern cu argumentele date; programul pornește abia la Run, Output sau Start.

Sintaxă
func Command(name string, arg ...string) *Cmd

Ce face exec.Command

exec.Command creează un *exec.Cmd care descrie comanda: programul și argumentele lui. Nu pornește nimic încă; pornirea se face cu Run, Output, CombinedOutput sau Start.

Dacă name nu conține separator de cale, programul este căutat în PATH (cu exec.LookPath). Argumentele se dau separat, nu ca un singur text: exec.Command("ls", "-l", "/tmp"). Go nu folosește un shell, deci *, |, > și $VAR nu au sens special. Pentru ele pornești explicit un shell: exec.Command("sh", "-c", "...").

Faptul că argumentele nu trec prin shell este și o protecție: un nume de fișier ca a; rm -rf ~ rămâne un singur argument inofensiv.

Parametri

Parametru Descriere
name Programul de rulat (nume din PATH sau cale).
arg Argumentele, fiecare separat.

Ce returnează

Un *exec.Cmd gata de configurat și pornit.

Exemple

Exemplul 1: Rularea unei comenzi și citirea rezultatului

package main

import (
    "fmt"
    "os/exec"
)

func main() {
    iesire, err := exec.Command("echo", "Salut", "din", "Iași").Output()
    if err != nil {
        fmt.Println("eroare:", err)
        return
    }
    fmt.Printf("%q\n", iesire)
}

Rezultat

"Salut din Iași\n"

Exemplul 2: Argumentele nu trec prin shell

Primul apel trimite textul *.txt neschimbat. Al doilea pornește un shell, care îl înlocuiește cu fișierele găsite.

package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    os.WriteFile("a.txt", nil, 0o644)
    os.WriteFile("b.txt", nil, 0o644)

    fara, _ := exec.Command("echo", "*.txt").Output()
    fmt.Print("fără shell: ", string(fara))

    cu, _ := exec.Command("sh", "-c", "echo *.txt").Output()
    fmt.Print("cu shell:   ", string(cu))
}

Rezultat

fără shell: *.txt
cu shell:   a.txt b.txt

Exemplul 3: Program inexistent

package main

import (
    "errors"
    "fmt"
    "os/exec"
)

func main() {
    err := exec.Command("program-care-nu-exista", "--ajutor").Run()
    fmt.Println(err)
    fmt.Println("negăsit:", errors.Is(err, exec.ErrNotFound))
}

Rezultat

exec: "program-care-nu-exista": executable file not found in $PATH
negăsit: true

Greșeli frecvente

  • Dai toată comanda ca un singur text: exec.Command("ls -l"). Go caută un program numit „ls -l”; separă argumentele.
  • Construiești o comandă sh -c din date primite de la utilizator. Oricine poate injecta comenzi; trimite datele ca argumente separate, fără shell.
  • Refolosești același Cmd de două ori. Un Cmd poate fi pornit o singură dată; creează altul.

Comenzi înrudite

  • exec.Cmd: Structura care descrie o comandă externă: programul, argumentele, directorul, mediul și intrarea/ieșirile ei.
  • exec.Cmd.Run: Pornește comanda și așteaptă să se termine; returnează eroare dacă nu a pornit sau a ieșit cu cod diferit de 0.
  • exec.Cmd.Output: Rulează comanda, așteaptă să se termine și returnează ce a scris pe ieșirea standard (stdout).
  • exec.CommandContext: Ca exec.Command, dar procesul este oprit automat când contextul expiră sau este anulat.
  • exec.LookPath: Caută un program executabil în directoarele din PATH și returnează calea lui.
  • os.StartProcess: Pornește un proces nou la nivel scăzut, cu programul, argumentele și fișierele date; de obicei folosești os/exec.