関連記事
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。
Goの中から、別のプロセスを起動して、その結果コードを受け取りたいことがたまにあります。
大した内容では無いのですが、やり方をいつも忘れるので、ここにメモメモ。。。
サンプル
起動するプロセスは何でも良いのですが、以下のようなドウでも良いプログラムを用意。
main.c
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i = atoi(argv[argc-1]); if (i >= 5) { exit(99-i); } if (i%2 == 0) { exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
C側をビルドするためのタスクファイルです。
Taskfile.yml (C)
# https://taskfile.dev version: '3' vars: C_APP: capp tasks: default: cmds: - task: run build: cmds: - gcc -o ../{{.C_APP}}{{exeExt}} main.c
利用するGo側のコード。
main.go
package main import ( "context" "errors" "fmt" "log" "os" "os/exec" "strconv" "time" ) func main() { var ( rootCtx = context.Background() mainCtx, mainCxl = context.WithTimeout(rootCtx, 1*time.Second) ) defer mainCxl() if err := run(mainCtx); err != nil { log.Fatal(err) } } func run(ctx context.Context) error { for i := range 10 { var ( ctx, cxl = context.WithTimeout(ctx, 100*time.Millisecond) program = os.Args[1] param = strconv.Itoa(i) cmd = exec.CommandContext(ctx, program, param) err error exitCode int success = true ) defer cxl() if err = cmd.Run(); err != nil { // // 結果コードが 0、つまり、成功の場合は err は nil となる。 // // 0以外の場合、errとして返ってくる。 // この場合、err は *exec.ExitError となっているので // errors.As() で、変換できるか確認し、ExitCode() で取得する。 // // Run() している最中に context がタイムアウトした場合 // 結果コードは -1 となって返ってくる。 // // Run() する前に context がタイムアウトした場合 // context.DeadlineExceeded が返ってくる。 // var exitErr *exec.ExitError if errors.As(err, &exitErr) { exitCode = exitErr.ExitCode() success = exitErr.Success() } else { // 別のエラーの場合 (context.DeadlineExceeded など) return err } } fmt.Printf("実行引数: %d\t成功: %v\t結果コード: %d\n", i, success, exitCode) } return nil }
Go側をビルドして実行するタスクファイルです。
Taskfile.yml (Go)
# https://taskfile.dev version: '3' vars: C_APP: capp GO_APP: goapp includes: C: taskfile: ./c/Taskfile.yml dir: ./c tasks: default: cmds: - task: run build: cmds: - task: C:build - go build -o {{.GO_APP}}{{exeExt}} main.go run: deps: [ build ] cmds: - ./{{.GO_APP}}{{exeExt}} "./{{.C_APP}}{{exeExt}}" clean: cmds: - rm -f ./{{.C_APP}}{{exeExt}} ./{{.GO_APP}}{{exeExt}}
実行すると以下のようになります。
shell
$ task task: [C:build] gcc -o ../capp main.c task: [build] go build -o goapp main.go task: [run] ./goapp "./capp" 実行引数: 0 成功: false 結果コード: 1 実行引数: 1 成功: true 結果コード: 0 実行引数: 2 成功: false 結果コード: 1 実行引数: 3 成功: true 結果コード: 0 実行引数: 4 成功: false 結果コード: 1 実行引数: 5 成功: false 結果コード: 94 実行引数: 6 成功: false 結果コード: 93 実行引数: 7 成功: false 結果コード: 92 実行引数: 8 成功: false 結果コード: 91 実行引数: 9 成功: false 結果コード: 90
try-golang/examples/singleapp/exit_code at main · devlights/try-golang · GitHub
参考情報
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。