Spawning Processes

Spawning Processes #

// တစ်ခါတလေမှာ ကျွန်တော်တို့ရဲ့ Go ပရိုဂရမ်တွေဟာ Go မဟုတ်တဲ့ တခြား
// လုပ်ငန်းစဉ် (processes) တွေကို လုပ်ဆောင်ဖို့ လိုအပ်ပါတယ်။

package main

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

func main() {

	// ကျွန်တော်တို့က argument တွေ၊ input တွေ မလိုအပ်ပဲ stdout ပေါ်မှာ တစ်ခုခုကို
	// ရိုက်ထုတ်ပြတဲ့ ရိုးရှင်းတဲ့ command တစ်ခုနဲ့ စမယ်။ `exec.Command` helper က
	// ဒီ ပြင်ပ လုပ်ငန်းစဉ်ကို ကိုယ်စားပြုဖို့ object တစ်ခုကို ဖန်တီးပေးပါတယ်။
	dateCmd := exec.Command("date")
	// `Output` method က command ကို run ပြီး အဆုံးသတ်တဲ့အထိ စောင့်ပြီး
	// သူ့ရဲ့ standard output ကို စုဆောင်းပါတယ်။
	// အမှားမရှိဘူးဆိုရင် `dateOut` မှာ ရက်စွဲအချက်အလက်ပါတဲ့ bytes တွေ ပါဝင်မှာဖြစ်ပါတယ်။
	dateOut, err := dateCmd.Output()
	if err != nil {
		panic(err)
	}
	fmt.Println("> date")
	fmt.Println(string(dateOut))
	// `Output` နဲ့ `Command` ရဲ့ တခြား method တွေဟာ command ကို run ဖို့
	// ပြဿနာရှိခဲ့ရင် (ဥပမာ - မှားယွင်းတဲ့လမ်းကြောင်း) `*exec.Error` ကို return ပြန်ပြီး၊
	// command က run ပေမယ့် non-zero return code နဲ့ ထွက်သွားခဲ့ရင်
	// `*exec.ExitError` ကို return ပြန်ပါတယ်။
	_, 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)
		}
	}

	// နောက်တစ်ဆင့်မှာ ပြင်ပလုပ်ငန်းစဉ်ရဲ့ `stdin` ပေါ်ကို data တွေ pipe လုပ်ပြီး
	// သူ့ရဲ့ `stdout` ကနေ ရလဒ်တွေကို စုဆောင်းတဲ့ နည်းနည်းပိုရှုပ်ထွေးတဲ့ ကိစ္စကို ကြည့်ကြမယ်။
	grepCmd := exec.Command("grep", "hello")

	// ဒီမှာတော့ input/output pipes တွေကို အတိအကျ ယူပြီး၊ လုပ်ငန်းစဉ်ကို စတင်၊
	// အထဲကို input တချို့ ရေးထည့်၊ ထွက်လာတဲ့ output ကို ဖတ်ယူပြီး နောက်ဆုံးမှာ
	// လုပ်ငန်းစဉ် ပြီးဆုံးတဲ့အထိ စောင့်ပါတယ်။
	grepIn, _ := grepCmd.StdinPipe()
	grepOut, _ := grepCmd.StdoutPipe()
	grepCmd.Start()
	grepIn.Write([]byte("hello grep\ngoodbye grep"))
	grepIn.Close()
	grepBytes, _ := io.ReadAll(grepOut)
	grepCmd.Wait()

	// အထက်ပါ ဥပမာမှာ အမှားစစ်ဆေးမှုတွေကို ချန်လှပ်ထားပါတယ်၊ ဒါပေမယ့်
	// သင်က ပုံမှန် `if err != nil` pattern ကို အားလုံးအတွက် သုံးနိုင်ပါတယ်။
	// ကျွန်တော်တို့က `StdoutPipe` ရလဒ်တွေကိုပဲ စုဆောင်းထားပေမယ့် သင်က
	// အတူတူပဲ `StderrPipe` ကိုလည်း စုဆောင်းနိုင်ပါတယ်။
	fmt.Println("> grep hello")
	fmt.Println(string(grepBytes))

	// မှတ်သားရန် - command တွေကို spawn လုပ်တဲ့အခါ command-line string တစ်ခုတည်းကို
	// ပေးနိုင်တာမဟုတ်ဘဲ၊ အတိအကျ သတ်မှတ်ထားတဲ့ command နဲ့ argument array ကို
	// ပေးဖို့ လိုအပ်ပါတယ်။ သင်က string တစ်ခုနဲ့ အပြည့်အစုံ command တစ်ခုကို
	// spawn လုပ်ချင်ရင် `bash` ရဲ့ `-c` option ကို သုံးနိုင်ပါတယ်။
	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))
}
# ဖန်တီးထားတဲ့ ပရိုဂရမ်တွေက ထွက်လာတဲ့ output ဟာ 
# ကျွန်တော်တို့ command-line ကနေ 
# တိုက်ရိုက် run သလိုပဲ ဖြစ်ပါတယ်။
$ go run spawning-processes.go 
> date
Thu 05 May 2022 10:10:12 PM PDT
# date မှာ `-x` flag မရှိတဲ့အတွက် 
# အမှားပြ message နဲ့အတူ 
# non-zero return code နဲ့ ထွက်သွားပါလိမ့်မယ်။
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 spawning-processes.go