os.StartProcess în Go

Pornește un proces nou la nivel scăzut, cu programul, argumentele și fișierele date; de obicei folosești os/exec.

Sintaxă
func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error)

Ce face os.StartProcess

os.StartProcess pornește direct un program. Spre deosebire de exec.Command, nu caută programul în PATH (name trebuie să fie o cale, de exemplu obținută cu exec.LookPath), iar argv conține și numele programului pe prima poziție (devine os.Args în procesul nou).

attr (*os.ProcAttr) descrie directorul (Dir), mediul (Env) și fișierele moștenite (Files: poziția 0 devine intrarea standard, 1 ieșirea, 2 erorile). Fișierele nedate rămân închise în copil, deci fără Files procesul nu are unde să scrie. Procesul pornit se așteaptă cu p.Wait(), care returnează un *os.ProcessState.

Documentația spune clar că este o interfață de nivel scăzut și că os/exec oferă una mai comodă. O vei întâlni rar.

Parametri

Parametru Descriere
name Calea programului.
argv Argumentele, începând cu numele programului.
attr Directorul, mediul și fișierele procesului nou.

Ce returnează

Un *os.Process și nil, sau o eroare *fs.PathError.

Exemple

Exemplul 1: Pornire și așteptare

package main

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

func main() {
    cale, err := exec.LookPath("echo")
    if err != nil {
        fmt.Println("eroare:", err)
        return
    }
    attr := &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}}
    p, err := os.StartProcess(cale, []string{"echo", "Salut", "din", "Sibiu"}, attr)
    if err != nil {
        fmt.Println("eroare:", err)
        return
    }
    stare, err := p.Wait()
    fmt.Println("terminat:", stare.Success(), "cod:", stare.ExitCode(), err)
}

Rezultat

Salut din Sibiu
terminat: true cod: 0 <nil>

Exemplul 2: Același lucru cu os/exec

Varianta recomandată: exec.Command caută programul și leagă singur ieșirile.

package main

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

func main() {
    cmd := exec.Command("echo", "Salut", "din", "Sibiu")
    cmd.Stdout = os.Stdout
    err := cmd.Run()
    fmt.Println("cod:", cmd.ProcessState.ExitCode(), err)
}

Rezultat

Salut din Sibiu
cod: 0 <nil>

Exemplul 3: Program inexistent

package main

import (
    "fmt"
    "os"
)

func main() {
    _, err := os.StartProcess("/nu/exista/backup", []string{"backup"}, &os.ProcAttr{})
    fmt.Println(err)
}

Rezultat

fork/exec /nu/exista/backup: no such file or directory

Greșeli frecvente

  • Dai doar numele programului ("ls"). StartProcess nu caută în PATH; folosește exec.LookPath sau, mai simplu, exec.Command.
  • Uiți numele programului din argv: []string{"-l"} face ca -l să fie os.Args[0], iar programul nu primește niciun argument.
  • Nu dai Files și te miri că nu apare nimic: procesul copil nu are ieșire standard.

Comenzi înrudite

  • exec.Command: Pregătește rularea unui program extern cu argumentele date; programul pornește abia la Run, Output sau Start.
  • os.FindProcess: Returnează un *os.Process pentru PID-ul dat, ca să-i poți trimite semnale, să-l oprești sau să-l aștepți.
  • exec.LookPath: Caută un program executabil în directoarele din PATH și returnează calea lui.
  • exec.Cmd: Structura care descrie o comandă externă: programul, argumentele, directorul, mediul și intrarea/ieșirile ei.