Go 言語で外部プロセスを生成する

GolangGolangBeginner
今すぐ練習

This tutorial is from open-source community. Access the source code

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

場合によっては、Go プログラムは非 Go プロセスを生成する必要があります。この実験では、Go で外部プロセスを生成する方法を示すことを目的としています。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("Golang")) -.-> go/NetworkingGroup(["Networking"]) go/NetworkingGroup -.-> go/processes("Processes") subgraph Lab Skills go/processes -.-> lab-15509{{"Go 言語で外部プロセスを生成する"}} end

プロセスの生成

この実験では、外部プロセスを生成してその出力を収集する Go プログラムの実装が必要です。

  • プログラムは外部プロセスを生成できる必要があります。
  • プログラムは外部プロセスの出力を収集できる必要があります。
  • プログラムは外部プロセスの実行中に発生する可能性のあるエラーを処理する必要があります。
## 生成されたプログラムは、コマンドラインから直接実行した場合と同じ出力を返します。
$ go run spawning-processes.go
> date
Thu 05 May 2022 10:10:12 PM PDT

## date には `-x` フラグがないため、エラーメッセージと非ゼロの戻りコードで終了します。
command exited with rc = 1
hello > grep
hello grep

-a > ls -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

以下に完全なコードがあります:

// 時々、私たちの Go プログラムは他の非 Go プロセスを生成する必要があります。

package main

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

func main() {

	// 最初に、引数や入力を必要とせず、単に何かを標準出力に出力する簡単なコマンドから始めます。`exec.Command` ヘルパーは、この外部プロセスを表すオブジェクトを作成します。
	dateCmd := exec.Command("date")

	// `Output` メソッドはコマンドを実行し、終了するのを待ち、その標準出力を収集します。エラーがなければ、`dateOut` に日付情報のバイトが格納されます。
	dateOut, err := dateCmd.Output()
	if err!= nil {
		panic(err)
	}
	fmt.Println("> date")
	fmt.Println(string(dateOut))

	// `Output` や `Command` の他のメソッドは、コマンドの実行に問題があった場合(たとえば、パスが間違っている場合)に `*exec.Error` を返し、コマンドが実行されたが非ゼロの戻りコードで終了した場合に `*exec.ExitError` を返します。
	_, 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` にデータをパイプし、`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()

	// 上の例ではエラーチェックを省略しましたが、すべてに対して通常の `if err!= nil` パターンを使用できます。また、`StdoutPipe` の結果のみを収集していますが、`StderrPipe` もまったく同じ方法で収集できます。
	fmt.Println("> grep hello")
	fmt.Println(string(grepBytes))

	// コマンドを生成する際には、明示的に区切られたコマンドと引数の配列を提供する必要があります。コマンドライン文字列を 1 つだけ渡せるわけではありません。文字列を使って完全なコマンドを生成する場合は、`bash` の `-c` オプションを使用できます:
	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))
}

まとめ

この実験では、exec パッケージを使用して Go で外部プロセスを生成する方法を示しました。このプログラムは、引数や入力を必要とせず、引数を受け取って標準出力に何かを出力し、標準入力から入力を受け取って標準出力に何かを出力し、文字列を使った完全なコマンドを受け取る外部プロセスを生成することができました。また、外部プロセスの実行中に発生する可能性のあるエラーも処理しました。