Golang processes: Difference between revisions

From wikinotes
Line 62: Line 62:


// must be read-from/written-to in go routine! (can be anonymous)
// must be read-from/written-to in go routine! (can be anonymous)
// ex. go func() { defer stdin.Close(); stdin.Write([]byte("foo")); }()  
// ex. go func() { defer stdin.Close(); stdin.Write([]byte("foo")); }()
reader, err := cmd.StderrPipe()
reader, err := cmd.StderrPipe()
reader, err := cmd.StdoutPipe()
reader, err := cmd.StdoutPipe()
Line 72: Line 72:
err := cmd.Wait()  // wait for proces to finish
err := cmd.Wait()  // wait for proces to finish
</syntaxhighlight>
</syntaxhighlight>
{{ expand
| StdinPipe example
|
<syntaxhighlight lang="go">
cmd := exec.Command("pandoc", "-f", "mediawiki", "-t", "rst")
stdin, _ := cmd.StdinPipe()
ch := make(chan, error)
go func(ch chan<- error) {
    defer stdin.Close()
    _, err := stdin.Write([]byte("abc"))
    ch <- err
}(ch)
cmd.Run()
</syntaxhighlight>
}}
{{ expand
| Stdout/Stderr example
|
<syntaxhighlight lang="go">
cmd := exec.Command("pandoc", "-f", "mediawiki", "-t", "rst", "foo.mediawiki")
stdout, _ := cmd.StdoutPipe()
defer stdout.Close()
cmd.Start()
out, _ := io.ReadAll(stdout)
cmd.Wait()
</syntaxhighlight>
}}


low-level
low-level

Revision as of 14:38, 1 July 2022

Start/Manage a process, or get information about system processes.

Documentation

os https://pkg.go.dev/os@go1.18.3

Current Process

import "os"
import "os/user"

os.Executable()
os.Getpid()
os.Getppid()
os.Getuid()
os.Getgid()

os.Exit(1)              // exit process with exitcode '1'

// environment
envvars := os.Environ() // ["FOO=bar", "BAR=baz", ...]
pwd, err := os.Getwd()  // get current pwd/cwd
user.Current()          // 'will'

Manage Processes

import "syscall"
import "os"
import "os/signal"

proc := os.Process.FindProcess(1234)  // find process with pid
proc.Kill()                           // kill process (-9/SIGKILL)
proc.Signal(os.Iterrupt)              // send SIGINT to process (looks like you can use any syscall.SIG*)
proc.Wait()                           // wait for process to end

syscall.Kill(1234, syscall.SIGINT)    // send SIGINT to pid 1234

Subprocess

high-level/friendly

// 1. create command,
// 2. modify it's exec.Cmd struct (ex. stdin,stdout)
// 3. run process
// 4. cmd.ProcessState has info about process, including exitcode
import "os"
import "os/exec"

cmd := exec.Command("netstat", "-an")
stdout, err := cmd.Output()

// must be read-from/written-to in go routine! (can be anonymous)
// ex. go func() { defer stdin.Close(); stdin.Write([]byte("foo")); }()
reader, err := cmd.StderrPipe()
reader, err := cmd.StdoutPipe()
writer, err := cmd.StdinPipe()

cmd.Process.Pid    // get pid (after starting process)
err := cmd.Run()   // run and wait
err := cmd.Start() // run, don't wait
err := cmd.Wait()  // wait for proces to finish

StdinPipe example


cmd := exec.Command("pandoc", "-f", "mediawiki", "-t", "rst")
stdin, _ := cmd.StdinPipe()
ch := make(chan, error)
go func(ch chan<- error) {
    defer stdin.Close()
    _, err := stdin.Write([]byte("abc"))
    ch <- err
}(ch)
cmd.Run()


Stdout/Stderr example

cmd := exec.Command("pandoc", "-f", "mediawiki", "-t", "rst", "foo.mediawiki")
stdout, _ := cmd.StdoutPipe()
defer stdout.Close()
cmd.Start()
out, _ := io.ReadAll(stdout)
cmd.Wait()

low-level

// 1. create ProcAttr
// 2. start process
// 3. wait for process
// 4. get info from it's ProcessState
import "os"
import "os/exec"

psAttr := os.ProcAttr{
    Dir: "/var/tmp",
    Env: []string{"FOO=BAR"},
}
ps := os.StartProcess("netstat", []string{"-a", "-n"}, psAttr)
pstate, err := ps.Wait()
pstate.ExitCode()

Reading from STDIN

stat, _ := os.Stdin.Stat()

if (stat.Mode() & os.ModeNamedPipe) == 0 {
    fmt.Println("Nothing to read on stdin")
    os.Exit(1)
} else {
    var reader = bufio.NewReader(os.Stdin)
    for {
        line, err := reader.ReadString('\n')
        if err == io.EOF {
            break
        }
        fmt.Print(line)
        time.Sleep(1 * time.Second)
    }
}