Ce face exec.CommandContext
exec.CommandContext leagă comanda de un context.Context. Dacă timpul contextului expiră sau cineva îl anulează înainte ca procesul să se termine, Go oprește procesul (implicit cu Kill). Este modul corect de a pune o limită de timp unei comenzi externe.
Din Go 1.20 poți schimba felul opririi prin câmpul cmd.Cancel (de exemplu trimiți întâi os.Interrupt) și poți da un timp de grație cu cmd.WaitDelay.
Parametri
| Parametru | Descriere |
|---|---|
ctx |
Contextul; de obicei din context.WithTimeout. |
name, arg |
Programul și argumentele, ca la exec.Command. |
Ce returnează
Un *exec.Cmd.
Exemple
Exemplul 1: Limită de timp
package main
import (
"context"
"fmt"
"os/exec"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel()
err := exec.CommandContext(ctx, "sleep", "5").Run()
fmt.Println("eroare:", err)
fmt.Println("context:", ctx.Err())
}
Rezultat
eroare: signal: killed
context: context deadline exceeded
Exemplul 2: Comanda termină la timp
package main
import (
"context"
"fmt"
"os/exec"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
iesire, err := exec.CommandContext(ctx, "echo", "backup terminat").Output()
fmt.Printf("%q %v\n", iesire, err)
}
Rezultat
"backup terminat\n" <nil>
Exemplul 3: Oprire politicoasă cu Cancel și WaitDelay
La expirare trimitem SIGINT în loc de Kill; scriptul prinde semnalul, face curățenie și iese singur.
package main
import (
"context"
"fmt"
"os"
"os/exec"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
defer cancel()
script := "trap 'echo curăț fișierele temporare; exit 1' INT; echo lucrez; sleep 5 & wait"
cmd := exec.CommandContext(ctx, "sh", "-c", script)
cmd.Cancel = func() error { return cmd.Process.Signal(os.Interrupt) }
cmd.WaitDelay = 2 * time.Second
iesire, err := cmd.Output()
fmt.Print(string(iesire))
fmt.Println("eroare:", err)
}
Rezultat
lucrez
curăț fișierele temporare
eroare: exit status 1
Greșeli frecvente
- Uiți
defer cancel(). Resursele contextului rămân ocupate până la expirare. - Pornești cu
sh -co comandă care lansează alte procese.Killoprește doar shell-ul, nu și copiii lui; foloseșteWaitDelayși, la nevoie, grupuri de procese.
Comenzi înrudite
exec.Command: Pregătește rularea unui program extern cu argumentele date; programul pornește abia la Run, Output sau Start.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.signal.NotifyContext: Returnează un context care se anulează când programul primește unul dintre semnalele date (de exemplu Ctrl+C).exec.Cmd.Start: Start pornește comanda fără să aștepte; Wait așteaptă terminarea ei și eliberează resursele.