Go بالأمثلة: بدء العمليات (Spawning Processes)

أحياناً يحتاج برنامج Go الخاص بنا إلى تشغيل برامج أخرى ليست مكتوبة بـ Go.

package main

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

func main() {

سنبدأ بأمر بسيط لا يأخذ أي معاملات أو مدخلات ويطبع فقط في المخرجات القياسية. الأداة المساعدة exec.Command تنشئ كائناً يمثل هذه العملية الخارجية.

    dateCmd := exec.Command("date")

Output هي دالة مساعدة أخرى تتعامل مع تشغيل الأمر، والانتظار حتى ينتهي، وجمع مخرجاته.

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

إذا حدث خطأ أثناء تشغيل الأمر (مثلاً إذا خرج بحالة غير صفرية)، فسيتم إرجاع خطأ يحتوي على تفاصيل الخروج.

    _, err = exec.Command("date", "-x").Output()
    if err != nil {
        fmt.Println("> date -x failed:", err)
    }

الآن سننظر في حالة أكثر تعقيداً حيث نقوم بضخ البيانات إلى العملية الخارجية عبر stdin وجمع النتائج من stdout.

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

هنا نستخرج صراحة أنابيب المدخلات والمخرجات.

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

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

لاحظ أننا عند تشغيل الأوامر نحتاج إلى تقديم الأمر والمعاملات بشكل منفصل. إذا كنت تريد تشغيل أمر كامل كنص، يمكنك استخدام خيار -c في 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))
}

تشغيل البرنامج:

$ go run spawning-processes.go 
> date
Wed Aug 23 10:52:11 PDT 2023
...

المثال التالي: استبدال العملية (Exec'ing Processes).