Program command line jarang berdiri sendiri: program membaca cara pemanggilannya dari argumen, membaca konfigurasi dari environment variable, dan melaporkan keberhasilan melalui kode keluar. Package os menjadi jembatan antara program Go dan sistem operasi untuk ketiganya. Chapter ini mempraktikkan os.Args, Getenv, Setenv, LookupEnv, Environ, standard stream, dan os.Exit dengan contoh yang dijalankan sungguhan.

Membaca Argumen dengan os.Args #

Variable os.Args adalah slice string yang memuat seluruh kata pada command line. Indeks 0 berisi nama program, sedangkan argumen pengguna dimulai dari indeks 1:

go
argumen := os.Args[1:]

Saat dijalankan lewat go run, indeks 0 berisi path binary sementara yang berubah di setiap eksekusi. Program demo karena itu hanya mencetak elemen mulai indeks 1 supaya output tetap stabil.

Environment Variable: Getenv, Setenv, dan LookupEnv #

Environment variable adalah pasangan kunci-nilai yang diwarisi program dari proses pemanggilnya. Fungsi os.Setenv membuat atau mengubah variabel; os.Getenv membaca nilainya. Perilaku keduanya saat variabel tidak ada berbeda:

Kondisi variabelos.Getenvos.LookupEnv
Ada, bernilai "produksi""produksi""produksi", true
Ada, bernilai kosong """""", true
Tidak ada"""", false

os.Getenv tidak bisa membedakan variabel kosong dari variabel yang tidak ada karena keduanya mengembalikan "". Fungsi os.LookupEnv mengembalikan nilai kedua bertipe boolean — bentuk dua-nilai ini (bahasa Inggris: comma ok idiom) menjawab keraguan tersebut.

Daftar Seluruh Variabel dengan os.Environ #

Fungsi os.Environ() mengembalikan slice string berformat KUNCI=nilai untuk seluruh variabel lingkungan. Isinya berbeda di setiap mesin, jadi program demo memakai pola stabil: menyaring variabel berprefiks PELATIHAN_ milik sendiri, lalu mengurutkannya dengan sort.Strings.

Standard Stream dan os.File #

os.Stdout, os.Stderr, dan os.Stdin bertipe *os.File. Tipe tersebut memenuhi interface io.Writer dan io.Reader, sehingga ketiganya bisa dipakai di fungsi mana pun yang menerima kedua interface itu — contohnya fmt.Fprintf(os.Stdout, ...). Untuk bekerja dengan berkas fisik, chapter Membaca File dan Menulis File membahas os.Open dan os.Create.

Program Utuh #

Berkas os-demo.go menggabungkan seluruh materi di atas:

go
package main

import (
	"fmt"
	"os"
	"sort"
	"strings"
)

func main() {
	// os.Args[0] berisi nama program; argumen pengguna mulai dari indeks 1.
	argumen := os.Args[1:]
	fmt.Println("jumlah argumen:", len(argumen))
	for indeks, nilai := range argumen {
		fmt.Printf("argumen[%d] = %s\n", indeks, nilai)
	}

	// Setenv membuat variabel lingkungan, Getenv membaca nilainya.
	os.Setenv("NAMA_APLIKASI", "kasir")
	fmt.Println("getenv NAMA_APLIKASI:", os.Getenv("NAMA_APLIKASI"))
	fmt.Printf("getenv VARIABEL_TIDAK_ADA: %q\n", os.Getenv("VARIABEL_TIDAK_ADA"))

	// LookupEnv melaporkan apakah variabel benar-benar ada.
	os.Setenv("MODE_APLIKASI", "produksi")
	mode, ada := os.LookupEnv("MODE_APLIKASI")
	fmt.Printf("lookupenv MODE_APLIKASI: %q ada: %v\n", mode, ada)

	kosong, hilang := os.LookupEnv("VARIABEL_TIDAK_ADA")
	fmt.Printf("lookupenv VARIABEL_TIDAK_ADA: %q ada: %v\n", kosong, hilang)

	// os.Environ memuat semua variabel; saring milik kita lalu urutkan.
	os.Setenv("PELATIHAN_KOTA", "Bandung")
	os.Setenv("PELATIHAN_MATERI", "standard library")
	terpilih := []string{}
	for _, kv := range os.Environ() {
		if strings.HasPrefix(kv, "PELATIHAN_") {
			terpilih = append(terpilih, kv)
		}
	}
	sort.Strings(terpilih)
	fmt.Println("environ terfilter:", strings.Join(terpilih, ", "))

	// os.Stdout bertipe *os.File dan memenuhi io.Writer.
	fmt.Fprintf(os.Stdout, "fmt.Fprintf ke os.Stdout berhasil\n")

	// os.Exit menghentikan program seketika; defer tidak dijalankan.
	defer fmt.Println("baris defer ini tidak pernah tercetak")
	fmt.Println("program selesai")
	os.Exit(0)
}

Jalankan tanpa argumen terlebih dahulu:

bash
go run os-demo.go

Output yang Dihasilkan:

text
jumlah argumen: 0
getenv NAMA_APLIKASI: kasir
getenv VARIABEL_TIDAK_ADA: ""
lookupenv MODE_APLIKASI: "produksi" ada: true
lookupenv VARIABEL_TIDAK_ADA: "" ada: false
environ terfilter: PELATIHAN_KOTA=Bandung, PELATIHAN_MATERI=standard library
fmt.Fprintf ke os.Stdout berhasil
program selesai

Kemudian jalankan lagi dengan dua argumen:

bash
go run os-demo.go Budi Siti

Output yang Dihasilkan:

text
jumlah argumen: 2
argumen[0] = Budi
argumen[1] = Siti
getenv NAMA_APLIKASI: kasir
getenv VARIABEL_TIDAK_ADA: ""
lookupenv MODE_APLIKASI: "produksi" ada: true
lookupenv VARIABEL_TIDAK_ADA: "" ada: false
environ terfilter: PELATIHAN_KOTA=Bandung, PELATIHAN_MATERI=standard library
fmt.Fprintf ke os.Stdout berhasil
program selesai

Mari kita telaah baris demi baris program di atas:

  1. Baris 12-16: os.Args[1:] mengambil argumen pengguna, lalu loop mencetak indeks dan nilai setiap argumen; tanpa argumen, loop tidak berputar sama sekali.
  2. Baris 19-21: os.Setenv membuat variabel NAMA_APLIKASI, os.Getenv membacanya kembali; verb %q memperlihatkan string kosong yang dikembalikan untuk variabel yang tidak ada.
  3. Baris 24-29: os.LookupEnv diuji pada dua kondisi — variabel yang ada (ada bernilai true) dan variabel yang hilang (hilang bernilai false).
  4. Baris 32-41: dua variabel berprefiks PELATIHAN_ dibuat, hasil os.Environ disaring dengan strings.HasPrefix, lalu sort.Strings menjamin urutan cetak yang tetap.
  5. Baris 44: fmt.Fprintf menulis ke os.Stdout, bukti bahwa *os.File memenuhi io.Writer.
  6. Baris 46-49: defer terdaftar pada baris 47, tetapi os.Exit(0) pada baris 49 menghentikan program sebelum baris defer tersebut sempat dijalankan.

Keluar Program dengan os.Exit #

Fungsi os.Exit menghentikan program seketika dengan kode status tertentu. Konvensinya: kode 0 berarti sukses, kode lain berarti gagal; script shell dan sistem CI membaca kode ini lewat $?.

Berkas os-exit-demo.go memperagakan kedua kode keluar:

go
package main

import (
	"fmt"
	"os"
)

func main() {
	kode := 0
	if len(os.Args) > 1 && os.Args[1] == "gagal" {
		kode = 1
	}
	fmt.Println("keluar dengan kode", kode)
	os.Exit(kode)
}

Tanpa argumen, program keluar dengan kode 0:

bash
go run os-exit-demo.go

Output yang Dihasilkan:

text
keluar dengan kode 0

Dengan argumen gagal, program keluar dengan kode 1 dan kode tersebut terbaca oleh $?:

bash
go run os-exit-demo.go gagal
echo "kode keluar: $?"

Output yang Dihasilkan:

text
keluar dengan kode 1
kode keluar: 1

Mari kita telaah baris demi baris program di atas:

  1. Baris 9 (kode := 0): menetapkan kode keluar bawaan, yaitu sukses.
  2. Baris 10-12: memeriksa argumen pertama; jika nilainya "gagal", kode keluar diubah menjadi 1.
  3. Baris 13: mencetak kode yang akan dipakai agar hasilnya terlihat di layar.
  4. Baris 14 (os.Exit(kode)): menghentikan program dan meneruskan kode sebagai status proses kepada sistem operasi.

Saat menguji lewat go run, perintah tersebut turut mencetak exit status 1 ke standard error; kode status tetap diteruskan ke $?.

Referensi #

Package os memberi akses mentah ke argumen, variabel lingkungan, dan kode keluar. Chapter berikutnya naik satu tingkat abstraksi ke package io: dua interface kecil bernama Reader dan Writer yang menjadi bahasa bersama seluruh input-output di Go.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

os-demo.go

Unduh berkas
go
package main

import (
	"fmt"
	"os"
	"sort"
	"strings"
)

func main() {
	// os.Args[0] berisi nama program; argumen pengguna mulai dari indeks 1.
	argumen := os.Args[1:]
	fmt.Println("jumlah argumen:", len(argumen))
	for indeks, nilai := range argumen {
		fmt.Printf("argumen[%d] = %s\n", indeks, nilai)
	}

	// Setenv membuat variabel lingkungan, Getenv membaca nilainya.
	os.Setenv("NAMA_APLIKASI", "kasir")
	fmt.Println("getenv NAMA_APLIKASI:", os.Getenv("NAMA_APLIKASI"))
	fmt.Printf("getenv VARIABEL_TIDAK_ADA: %q\n", os.Getenv("VARIABEL_TIDAK_ADA"))

	// LookupEnv melaporkan apakah variabel benar-benar ada.
	os.Setenv("MODE_APLIKASI", "produksi")
	mode, ada := os.LookupEnv("MODE_APLIKASI")
	fmt.Printf("lookupenv MODE_APLIKASI: %q ada: %v\n", mode, ada)

	kosong, hilang := os.LookupEnv("VARIABEL_TIDAK_ADA")
	fmt.Printf("lookupenv VARIABEL_TIDAK_ADA: %q ada: %v\n", kosong, hilang)

	// os.Environ memuat semua variabel; saring milik kita lalu urutkan.
	os.Setenv("PELATIHAN_KOTA", "Bandung")
	os.Setenv("PELATIHAN_MATERI", "standard library")
	terpilih := []string{}
	for _, kv := range os.Environ() {
		if strings.HasPrefix(kv, "PELATIHAN_") {
			terpilih = append(terpilih, kv)
		}
	}
	sort.Strings(terpilih)
	fmt.Println("environ terfilter:", strings.Join(terpilih, ", "))

	// os.Stdout bertipe *os.File dan memenuhi io.Writer.
	fmt.Fprintf(os.Stdout, "fmt.Fprintf ke os.Stdout berhasil\n")

	// os.Exit menghentikan program seketika; defer tidak dijalankan.
	defer fmt.Println("baris defer ini tidak pernah tercetak")
	fmt.Println("program selesai")
	os.Exit(0)
}

os-exit-demo.go

Unduh berkas
go
package main

import (
	"fmt"
	"os"
)

func main() {
	kode := 0
	if len(os.Args) > 1 && os.Args[1] == "gagal" {
		kode = 1
	}
	fmt.Println("keluar dengan kode", kode)
	os.Exit(kode)
}