Go by Example: Creazione Processi

A volte i nostri programmi Go devono creare altri processi non-Go.

package main
import (
    "fmt"
    "io"
    "os/exec"
)
func main() {

Inizieremo con un comando semplice che non prende argomenti o input e stampa solo qualcosa su stdout. L’helper exec.Command crea un oggetto per rappresentare questo processo esterno.

    dateCmd := exec.Command("date")

Il metodo Output esegue il comando, aspetta che finisca e raccoglie il suo output standard. Se non ci sono errori, dateOut conterrà i byte con le informazioni della data.

    dateOut, err := dateCmd.Output()
    if err != nil {
        panic(err)
    }
    fmt.Println("> date")
    fmt.Println(string(dateOut))

Output e altri metodi di Command restituiranno *exec.Error se c’è stato un problema nell’eseguire il comando (es. percorso sbagliato), e *exec.ExitError se il comando è stato eseguito ma è uscito con un codice di ritorno diverso da zero.

    _, err = exec.Command("date", "-x").Output()
    if err != nil {
        switch e := err.(type) {
        case *exec.Error:
            fmt.Println("failed executing:", err)
        case *exec.ExitError:
            fmt.Println("command exit rc =", e.ExitCode())
        default:
            panic(err)
        }
    }

Ora vedremo un caso leggermente più complesso dove inviamo dati al processo esterno sul suo stdin e raccogliamo i risultati dal suo stdout.

    grepCmd := exec.Command("grep", "hello")

Qui prendiamo esplicitamente le pipe di input/output, avviamo il processo, scriviamo dell’input ad esso, leggiamo l’output risultante e infine aspettiamo che il processo esca.

    grepIn, _ := grepCmd.StdinPipe()
    grepOut, _ := grepCmd.StdoutPipe()
    grepCmd.Start()
    grepIn.Write([]byte("hello grep\ngoodbye grep"))
    grepIn.Close()
    grepBytes, _ := io.ReadAll(grepOut)
    grepCmd.Wait()

Abbiamo omesso i controlli degli errori nell’esempio sopra, ma potresti usare il solito pattern if err != nil per tutti. Raccogliamo anche solo i risultati di StdoutPipe, ma potresti raccogliere StderrPipe nello stesso identico modo.

    fmt.Println("> grep hello")
    fmt.Println(string(grepBytes))

Nota che quando creiamo comandi dobbiamo fornire un comando e un array di argomenti esplicitamente delineati, invece di poter passare una sola stringa da riga di comando. Se vuoi creare un comando completo con una stringa, puoi usare l’opzione -c di bash:

    lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
    lsOut, err := lsCmd.Output()
    if err != nil {
        panic(err)
    }
    fmt.Println("> ls -a -l -h")
    fmt.Println(string(lsOut))
}

I programmi creati restituiscono output che è lo stesso come se li avessimo eseguiti direttamente dalla riga di comando.

$ go run creazione-processi.go 
> date
Thu 05 May 2022 10:10:12 PM PDT

date non ha un flag -x quindi uscirà con un messaggio di errore e codice di ritorno diverso da zero.

command exited with rc = 1
> grep hello
hello grep
> ls -a -l -h
drwxr-xr-x  4 mark 136B Oct 3 16:29 .
drwxr-xr-x 91 mark 3.0K Oct 3 12:50 ..
-rw-r--r--  1 mark 1.3K Oct 3 16:28 creazione-processi.go

Prossimo esempio: .