os.Exit în Go

Oprește imediat programul cu codul de ieșire dat; funcțiile amânate cu defer nu mai rulează.

Sintaxă
func Exit(code int)

Ce face os.Exit

os.Exit termină procesul pe loc. Codul de ieșire spune sistemului (sau scriptului care a pornit programul) cum s-a terminat: 0 = succes, orice altă valoare (de obicei 1) = eroare. În shell îl vezi cu echo $?.

Foarte important: os.Exit NU rulează funcțiile amânate cu defer. Fișierele nu sunt închise de defer f.Close(), buffer-ele bufio.Writer nu sunt golite. Un model des folosit este o funcție run() error care face toată treaba (cu defer-uri), iar main apelează os.Exit(1) doar dacă ea returnează eroare.

Parametri

Parametru Descriere
code Codul de ieșire: 0 pentru succes, 1–125 pentru erori.

Ce returnează

Nu se întoarce niciodată.

Exemple

Exemplul 1: defer nu rulează

package main

import (
    "fmt"
    "os"
)

func main() {
    defer fmt.Println("acest mesaj NU apare")
    fmt.Println("închidem programul")
    os.Exit(0)
}

Rezultat

închidem programul

Exemplul 2: Codul de ieșire văzut din shell

Programul verifică dacă a primit un nume de fișier și iese cu codul 2 dacă nu.

package main

import (
    "fmt"
    "os"
)

func main() {
    if len(os.Args) < 2 {
        fmt.Fprintln(os.Stderr, "utilizare: verifica <fisier>")
        os.Exit(2)
    }
    fmt.Println("verific", os.Args[1])
}

Rezultat în terminal

$ go build -o verifica . && ./verifica; echo "cod: $?"
utilizare: verifica <fisier>
cod: 2
$ ./verifica note.txt; echo "cod: $?"
verific note.txt
cod: 0

Exemplul 3: Modelul run() + os.Exit

Programul se pornește pe el însuși ca proces copil (cu argumentul copil), ca să putem vedea codul de ieșire. În copil, defer-ul din run rulează, pentru că os.Exit vine abia după ce run s-a terminat.

package main

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

func run() error {
    defer fmt.Println("run: închid fișierele (defer)")
    return errors.New("fișierul comenzi.csv lipsește")
}

func main() {
    if len(os.Args) > 1 && os.Args[1] == "copil" {
        if err := run(); err != nil {
            fmt.Println("eroare:", err)
            os.Exit(1)
        }
        return
    }

    exe, _ := os.Executable()
    iesire, err := exec.Command(exe, "copil").CombinedOutput()
    fmt.Print(string(iesire))
    var ee *exec.ExitError
    if errors.As(err, &ee) {
        fmt.Println("codul de ieșire al copilului:", ee.ExitCode())
    }
}

Rezultat

run: închid fișierele (defer)
eroare: fișierul comenzi.csv lipsește
codul de ieșire al copilului: 1

Greșeli frecvente

  • Apelezi os.Exit când mai ai date într-un bufio.Writer sau fișiere deschise cu defer Close(). Datele se pierd; golește-le înainte sau folosește modelul cu run().
  • Folosești os.Exit în bibliotecă (alt pachet decât main). O bibliotecă returnează erori; doar main decide când se oprește programul.
  • Ieși cu os.Exit(0) după o eroare. Scripturile și sistemele de CI cred atunci că totul a mers bine.

Comenzi înrudite

  • log.Fatal: Scrie mesajul în jurnal și oprește imediat programul cu codul 1 (ca log.Print urmat de os.Exit(1)).
  • 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.
  • os.Executable: Returnează calea fișierului executabil care rulează acum (programul compilat).