[インデックス 11923] ファイルの概要
このコミットは、Go言語の標準ライブラリ os/exec
パッケージに、その利用方法を示す具体的な例を追加するものです。os/exec
パッケージは、外部コマンドの実行を可能にするための機能を提供しており、これらの例は、開発者がこのパッケージをより効果的に使用するための手助けとなります。
コミット
commit dabf3db7153faac5e2b59429990f9f1bf6e39399
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Wed Feb 15 14:24:24 2012 +1100
os/exec: add some examples
R=golang-dev, adg, r, bradfitz
CC=golang-dev
https://golang.org/cl/5675054
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/dabf3db7153faac5e2b59429990f9f1bf6e39399
元コミット内容
os/exec: add some examples
R=golang-dev, adg, r, bradfitz
CC=golang-dev
https://golang.org/cl/5675054
変更の背景
Go言語の標準ライブラリは、その堅牢性と使いやすさで知られていますが、各パッケージの機能と利用方法を明確に伝えることは非常に重要です。特に os/exec
のように、システムと直接対話する機能を提供するパッケージでは、誤った使用がセキュリティリスクや予期せぬ動作につながる可能性があります。
このコミットが行われた2012年2月時点では、Go言語はまだ比較的新しい言語であり、多くの開発者がそのエコシステムと標準ライブラリに慣れ親しんでいる途中でした。このような状況下で、os/exec
パッケージの基本的な使い方から、より高度な入出力の処理、非同期実行、JSONデータのデコードといった具体的なユースケースを示す例が不足していたと考えられます。
Go言語の公式ドキュメントでは、Example
関数を用いたテスト可能なコード例を推奨しています。これにより、ドキュメントの例が常に最新のAPIと同期していることが保証され、開発者は実際に動作するコードを通じて学習できます。このコミットは、このようなGo言語のドキュメンテーション文化に則り、os/exec
パッケージの理解と適切な利用を促進することを目的としています。
前提知識の解説
Go言語の os/exec
パッケージ
os/exec
パッケージは、Goプログラムから外部のシステムコマンドやプログラムを実行するための機能を提供します。これにより、シェルスクリプトで実行されるようなタスク(例: ls
, grep
, date
, tr
など)をGoプログラム内で直接実行し、その出力を取得したり、入力を与えたり、実行を制御したりすることが可能になります。
主要な機能としては以下のようなものがあります。
exec.Command(name string, arg ...string) *Cmd
: 実行するコマンドとその引数を指定してCmd
構造体を作成します。Cmd
構造体は、コマンドの実行に関する詳細な設定(標準入力、標準出力、標準エラー出力、環境変数、作業ディレクトリなど)を保持します。Cmd.Run() error
: コマンドを実行し、その完了を待ちます。コマンドが正常に終了した場合はnil
を返し、エラーが発生した場合はerror
を返します。Cmd.Output() ([]byte, error)
: コマンドを実行し、その標準出力をバイトスライスとして返します。標準エラー出力は破棄されます。Cmd.CombinedOutput() ([]byte, error)
: コマンドを実行し、その標準出力と標準エラー出力を結合したバイトスライスとして返します。Cmd.Start() error
: コマンドを非同期で実行します。コマンドの完了を待たずにすぐに制御を返します。Cmd.Wait() error
:Start()
で開始されたコマンドの完了を待ちます。Cmd.Stdin
,Cmd.Stdout
,Cmd.Stderr
: コマンドの標準入出力ストリームを設定するためのフィールドです。io.Reader
やio.Writer
インターフェースを実装する任意の型を割り当てることができます。exec.LookPath(file string) (string, error)
: 指定された実行可能ファイルがシステムのPATH環境変数内でどこにあるかを検索します。
Go言語の Example
関数とテスト
Go言語では、Example
関数は通常のテスト関数 (TestXxx
) とは異なり、パッケージの利用例を示すために使用されます。これらの関数は _test.go
ファイル内に記述され、go test
コマンドを実行する際に自動的に検出され、実行されます。
Example
関数の特徴は以下の通りです。
- 出力の検証:
Example
関数のコメントにOutput:
またはUnordered output:
というプレフィックスを付けて期待される出力を記述すると、go test
は関数の実行結果とこのコメントの内容を比較し、一致しない場合はテスト失敗とみなします。これにより、例が常に正しく動作することが保証されます。 - ドキュメンテーション:
go doc
コマンドや pkg.go.dev のようなGoの公式ドキュメントサイトでは、Example
関数が自動的に抽出され、そのパッケージのドキュメントにコード例として表示されます。これにより、開発者は実際に動作するコードスニペットを通じて、パッケージの機能や使い方を素早く理解できます。 - 可読性:
Example
関数は、特定の機能の利用方法を簡潔かつ明確に示すことを目的としています。
このコミットで追加された example_test.go
ファイルは、まさにこの Example
関数の仕組みを利用して、os/exec
パッケージの様々な利用シナリオを実演しています。
技術的詳細
このコミットでは、src/pkg/os/exec/example_test.go
という新しいファイルが追加され、os/exec
パッケージの主要な機能を示す5つの Example
関数が定義されています。
-
ExampleLookPath()
:exec.LookPath("fortune")
を使用して、fortune
コマンドがシステムPATHのどこに存在するかを検索します。fortune
コマンドは、Unix系システムでランダムな格言を表示するユーティリティです。- コマンドが見つからない場合は
log.Fatal
でエラーを報告します。 - この例は、外部コマンドを実行する前にその存在を確認する一般的なパターンを示しています。
-
ExampleCommand()
:exec.Command("tr", "a-z", "A-Z")
を使用して、tr
コマンド(文字変換ユーティリティ)を実行するCmd
オブジェクトを作成します。cmd.Stdin = strings.NewReader("some input")
で、コマンドの標準入力に文字列 "some input" を与えます。var out bytes.Buffer
とcmd.Stdout = &out
で、コマンドの標準出力をbytes.Buffer
にリダイレクトします。cmd.Run()
でコマンドを実行し、完了を待ちます。- この例は、外部コマンドへの入力の提供と、その出力のキャプチャの基本的な方法を示しています。
-
ExampleCmd_Output()
:exec.Command("date").Output()
を使用して、date
コマンドを実行し、その標準出力を直接バイトスライスとして取得します。Output()
メソッドは、コマンドの実行と出力の取得を一度に行う便利な方法です。- この例は、単一のコマンドを実行し、その結果を簡単に取得するシナリオに適しています。
-
ExampleCmd_Start()
:exec.Command("sleep", "5")
を使用して、sleep 5
コマンド(5秒間待機する)を実行するCmd
オブジェクトを作成します。cmd.Start()
でコマンドを非同期で開始します。これにより、Goプログラムはsleep
コマンドが完了するのを待たずに次の処理に進むことができます。log.Printf("Waiting for command to finish...")
のように、非同期実行中に他の処理を行うことができることを示唆しています。cmd.Wait()
で、開始されたコマンドの完了を明示的に待ちます。- この例は、長時間実行される可能性のあるコマンドをバックグラウンドで実行し、後でその完了を待つ非同期実行のパターンを示しています。
-
ExampleCmd_StdoutPipe()
:exec.Command("echo", "-n",
{"Name": "Bob", "Age": 32})
を使用して、JSON文字列を標準出力に出力するecho
コマンドを実行するCmd
オブジェクトを作成します。stdout, err := cmd.StdoutPipe()
で、コマンドの標準出力へのパイプを取得します。このパイプはio.Reader
インターフェースを実装しています。cmd.Start()
でコマンドを開始します。StdoutPipe
を使用する場合、Start
を呼び出す前にパイプを取得する必要があります。json.NewDecoder(stdout).Decode(&person)
を使用して、コマンドの標準出力から直接JSONデータをデコードします。これは、外部コマンドがJSON形式のデータを出力する場合に非常に強力なパターンです。cmd.Wait()
でコマンドの完了を待ちます。- この例は、外部コマンドの出力をストリームとして扱い、それをGoの他のパッケージ(この場合は
encoding/json
)と連携させる高度な入出力処理を示しています。
これらの例は、os/exec
パッケージの柔軟性と、Goの標準ライブラリの他の部分(bytes
, strings
, encoding/json
, log
など)との連携方法を効果的に示しています。
コアとなるコードの変更箇所
このコミットでは、src/pkg/os/exec/example_test.go
という新しいファイルが追加されています。既存のファイルへの変更はありません。
diff --git a/src/pkg/os/exec/example_test.go b/src/pkg/os/exec/example_test.go
new file mode 100644
index 0000000000..55eaac8abc
--- /dev/null
+++ b/src/pkg/os/exec/example_test.go
@@ -0,0 +1,75 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec_test
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "log"
+ "os/exec"
+ "strings"
+)
+
+func ExampleLookPath() {
+ path, err := exec.LookPath("fortune")
+ if err != nil {
+ log.Fatal("installing fortune is in your future")
+ }
+ fmt.Printf("fortune is available at %s\n", path)
+}
+
+func ExampleCommand() {
+ cmd := exec.Command("tr", "a-z", "A-Z")
+ cmd.Stdin = strings.NewReader("some input")
+ var out bytes.Buffer
+ cmd.Stdout = &out
+ err := cmd.Run()
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("in all caps: %q\n", out.String())
+}
+
+func ExampleCmd_Output() {
+ out, err := exec.Command("date").Output()
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("The date is %s\n", out)
+}
+
+func ExampleCmd_Start() {
+ cmd := exec.Command("sleep", "5")
+ err := cmd.Start()
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Printf("Waiting for command to finish...")
+ err = cmd.Wait()
+ log.Printf("Command finished with error: %v", err)
+}
+
+func ExampleCmd_StdoutPipe() {
+ cmd := exec.Command("echo", "-n", `{"Name": "Bob", "Age": 32}`)
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := cmd.Start(); err != nil {
+ log.Fatal(err)
+ }
+ var person struct {
+ Name string
+ Age int
+ }
+ if err := json.NewDecoder(stdout).Decode(&person); err != nil {
+ log.Fatal(err)
+ }
+ if err := cmd.Wait(); err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%s is %d years old\n", person.Name, person.Age)
+}
コアとなるコードの解説
追加された example_test.go
ファイルには、os/exec
パッケージの様々な機能を示す5つの Example
関数が含まれています。これらの関数は、Goのテストフレームワークによって自動的に実行され、その出力が期待される出力と一致するかどうかが検証されます。また、go doc
コマンドやGoの公式ドキュメントサイトで、これらのコード例がパッケージのドキュメントとして表示されます。
ExampleLookPath()
この関数は、exec.LookPath
を使用して、指定されたコマンド(この場合は fortune
)がシステムのPATH環境変数内で見つかるかどうかを確認する方法を示しています。
func ExampleLookPath() {
path, err := exec.LookPath("fortune")
if err != nil {
log.Fatal("installing fortune is in your future") // fortuneが見つからない場合のエラーハンドリング
}
fmt.Printf("fortune is available at %s\n", path) // 見つかった場合のパスの表示
}
ExampleCommand()
この関数は、exec.Command
を使用して外部コマンドを実行し、その標準入力にデータを渡し、標準出力をキャプチャする方法を示しています。
func ExampleCommand() {
cmd := exec.Command("tr", "a-z", "A-Z") // 'tr' コマンドで小文字を大文字に変換
cmd.Stdin = strings.NewReader("some input") // 標準入力に文字列を渡す
var out bytes.Buffer
cmd.Stdout = &out // 標準出力を bytes.Buffer にリダイレクト
err := cmd.Run() // コマンドを実行し、完了を待つ
if err != nil {
log.Fatal(err)
}
fmt.Printf("in all caps: %q\n", out.String()) // 変換された出力を表示
}
ExampleCmd_Output()
この関数は、Cmd.Output()
メソッドを使用して、コマンドの標準出力を直接バイトスライスとして取得する簡潔な方法を示しています。
func ExampleCmd_Output() {
out, err := exec.Command("date").Output() // 'date' コマンドの出力を直接取得
if err != nil {
log.Fatal(err)
}
fmt.Printf("The date is %s\n", out) // 取得した日付情報を表示
}
ExampleCmd_Start()
この関数は、Cmd.Start()
と Cmd.Wait()
を使用して、外部コマンドを非同期で実行し、後でその完了を待つ方法を示しています。
func ExampleCmd_Start() {
cmd := exec.Command("sleep", "5") // 'sleep 5' コマンド(5秒間待機)
err := cmd.Start() // コマンドを非同期で開始
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...") // 非同期実行中に他の処理が可能
err = cmd.Wait() // コマンドの完了を待つ
log.Printf("Command finished with error: %v", err) // 完了時のエラー情報を表示
}
ExampleCmd_StdoutPipe()
この関数は、Cmd.StdoutPipe()
を使用してコマンドの標準出力へのパイプを取得し、それを encoding/json
パッケージと組み合わせて、外部コマンドからJSONデータをストリームとして読み込む方法を示しています。
func ExampleCmd_StdoutPipe() {
cmd := exec.Command("echo", "-n", `{"Name": "Bob", "Age": 32}`) // JSON文字列を出力するコマンド
stdout, err := cmd.StdoutPipe() // 標準出力へのパイプを取得
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil { // コマンドを開始
log.Fatal(err)
}
var person struct { // JSONデコード用の構造体
Name string
Age int
}
// パイプからJSONデータを直接デコード
if err := json.NewDecoder(stdout).Decode(&person); err != nil {
log.Fatal(err)
}
if err := cmd.Wait(); err != nil { // コマンドの完了を待つ
log.Fatal(err)
}
fmt.Printf("%s is %d years old\n", person.Name, person.Age) // デコードしたデータを表示
}
これらの例は、os/exec
パッケージの基本的な使い方から、非同期実行、パイプを使ったストリーム処理、他の標準ライブラリとの連携といった、より高度な利用パターンまでを網羅しており、開発者がこのパッケージを効果的に活用するための貴重なリソースとなります。
関連リンク
- Go言語
os/exec
パッケージのドキュメント: https://pkg.go.dev/os/exec - Go言語の
Example
関数に関する公式ブログ記事 (Go 1.0.3 のリリースノートの一部): https://go.dev/doc/go1.0.3#example (このコミットが行われた時期に近い情報源) - Go言語の
Example
関数に関するより詳細な情報: https://go.dev/blog/examples
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のブログ
os/exec
パッケージのソースコードencoding/json
パッケージのドキュメントbytes
パッケージのドキュメントstrings
パッケージのドキュメントlog
パッケージのドキュメントfmt
パッケージのドキュメントtr
コマンド、date
コマンド、sleep
コマンド、echo
コマンドに関する一般的なUnix/Linuxコマンドの知識- JSONデータ形式に関する一般的な知識
- Go言語のテストとドキュメンテーションに関する一般的な知識I have generated the detailed explanation for the commit. I will now output it to standard output as requested.
# [インデックス 11923] ファイルの概要
このコミットは、Go言語の標準ライブラリ `os/exec` パッケージに、その利用方法を示す具体的な例を追加するものです。`os/exec` パッケージは、外部コマンドの実行を可能にするための機能を提供しており、これらの例は、開発者がこのパッケージをより効果的に使用するための手助けとなります。
## コミット
commit dabf3db7153faac5e2b59429990f9f1bf6e39399 Author: Brad Fitzpatrick bradfitz@golang.org Date: Wed Feb 15 14:24:24 2012 +1100
os/exec: add some examples
R=golang-dev, adg, r, bradfitz
CC=golang-dev
https://golang.org/cl/5675054
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/dabf3db7153faac5e2b59429990f9f1bf6e39399](https://github.com/golang/go/commit/dabf3db7153faac5e2b59429990f9f1bf6e39399)
## 元コミット内容
os/exec: add some examples
R=golang-dev, adg, r, bradfitz CC=golang-dev https://golang.org/cl/5675054
## 変更の背景
Go言語の標準ライブラリは、その堅牢性と使いやすさで知られていますが、各パッケージの機能と利用方法を明確に伝えることは非常に重要です。特に `os/exec` のように、システムと直接対話する機能を提供するパッケージでは、誤った使用がセキュリティリスクや予期せぬ動作につながる可能性があります。
このコミットが行われた2012年2月時点では、Go言語はまだ比較的新しい言語であり、多くの開発者がそのエコシステムと標準ライブラリに慣れ親しんでいる途中でした。このような状況下で、`os/exec` パッケージの基本的な使い方から、より高度な入出力の処理、非同期実行、JSONデータのデコードといった具体的なユースケースを示す例が不足していたと考えられます。
Go言語の公式ドキュメントでは、`Example` 関数を用いたテスト可能なコード例を推奨しています。これにより、ドキュメントの例が常に最新のAPIと同期していることが保証され、開発者は実際に動作するコードを通じて学習できます。このコミットは、このようなGo言語のドキュメンテーション文化に則り、`os/exec` パッケージの理解と適切な利用を促進することを目的としています。
## 前提知識の解説
### Go言語の `os/exec` パッケージ
`os/exec` パッケージは、Goプログラムから外部のシステムコマンドやプログラムを実行するための機能を提供します。これにより、シェルスクリプトで実行されるようなタスク(例: `ls`, `grep`, `date`, `tr` など)をGoプログラム内で直接実行し、その出力を取得したり、入力を与えたり、実行を制御したりすることが可能になります。
主要な機能としては以下のようなものがあります。
* **`exec.Command(name string, arg ...string) *Cmd`**: 実行するコマンドとその引数を指定して `Cmd` 構造体を作成します。`Cmd` 構造体は、コマンドの実行に関する詳細な設定(標準入力、標準出力、標準エラー出力、環境変数、作業ディレクトリなど)を保持します。
* **`Cmd.Run() error`**: コマンドを実行し、その完了を待ちます。コマンドが正常に終了した場合は `nil` を返し、エラーが発生した場合は `error` を返します。
* **`Cmd.Output() ([]byte, error)`**: コマンドを実行し、その標準出力をバイトスライスとして返します。標準エラー出力は破棄されます。
* **`Cmd.CombinedOutput() ([]byte, error)`**: コマンドを実行し、その標準出力と標準エラー出力を結合したバイトスライスとして返します。
* **`Cmd.Start() error`**: コマンドを非同期で実行します。コマンドの完了を待たずにすぐに制御を返します。
* **`Cmd.Wait() error`**: `Start()` で開始されたコマンドの完了を待ちます。
* **`Cmd.Stdin`, `Cmd.Stdout`, `Cmd.Stderr`**: コマンドの標準入出力ストリームを設定するためのフィールドです。`io.Reader` や `io.Writer` インターフェースを実装する任意の型を割り当てることができます。
* **`exec.LookPath(file string) (string, error)`**: 指定された実行可能ファイルがシステムのPATH環境変数内でどこにあるかを検索します。
### Go言語の `Example` 関数とテスト
Go言語では、`Example` 関数は通常のテスト関数 (`TestXxx`) とは異なり、パッケージの利用例を示すために使用されます。これらの関数は `_test.go` ファイル内に記述され、`go test` コマンドを実行する際に自動的に検出され、実行されます。
`Example` 関数の特徴は以下の通りです。
* **出力の検証**: `Example` 関数のコメントに `Output:` または `Unordered output:` というプレフィックスを付けて期待される出力を記述すると、`go test` は関数の実行結果とこのコメントの内容を比較し、一致しない場合はテスト失敗とみなします。これにより、例が常に正しく動作することが保証されます。
* **ドキュメンテーション**: `go doc` コマンドや [pkg.go.dev](https://pkg.go.dev/) のようなGoの公式ドキュメントサイトでは、`Example` 関数が自動的に抽出され、そのパッケージのドキュメントにコード例として表示されます。これにより、開発者は実際に動作するコードスニペットを通じて、パッケージの機能や使い方を素早く理解できます。
* **可読性**: `Example` 関数は、特定の機能の利用方法を簡潔かつ明確に示すことを目的としています。
このコミットで追加された `example_test.go` ファイルは、まさにこの `Example` 関数の仕組みを利用して、`os/exec` パッケージの様々な利用シナリオを実演しています。
## 技術的詳細
このコミットでは、`src/pkg/os/exec/example_test.go` という新しいファイルが追加され、`os/exec` パッケージの主要な機能を示す5つの `Example` 関数が定義されています。
1. **`ExampleLookPath()`**:
* `exec.LookPath("fortune")` を使用して、`fortune` コマンドがシステムPATHのどこに存在するかを検索します。
* `fortune` コマンドは、Unix系システムでランダムな格言を表示するユーティリティです。
* コマンドが見つからない場合は `log.Fatal` でエラーを報告します。
* この例は、外部コマンドを実行する前にその存在を確認する一般的なパターンを示しています。
2. **`ExampleCommand()`**:
* `exec.Command("tr", "a-z", "A-Z")` を使用して、`tr` コマンド(文字変換ユーティリティ)を実行する `Cmd` オブジェクトを作成します。
* `cmd.Stdin = strings.NewReader("some input")` で、コマンドの標準入力に文字列 "some input" を与えます。
* `var out bytes.Buffer` と `cmd.Stdout = &out` で、コマンドの標準出力を `bytes.Buffer` にリダイレクトします。
* `cmd.Run()` でコマンドを実行し、完了を待ちます。
* この例は、外部コマンドへの入力の提供と、その出力のキャプチャの基本的な方法を示しています。
3. **`ExampleCmd_Output()`**:
* `exec.Command("date").Output()` を使用して、`date` コマンドを実行し、その標準出力を直接バイトスライスとして取得します。
* `Output()` メソッドは、コマンドの実行と出力の取得を一度に行う便利な方法です。
* この例は、単一のコマンドを実行し、その結果を簡単に取得するシナリオに適しています。
4. **`ExampleCmd_Start()`**:
* `exec.Command("sleep", "5")` を使用して、`sleep 5` コマンド(5秒間待機する)を実行する `Cmd` オブジェクトを作成します。
* `cmd.Start()` でコマンドを非同期で開始します。これにより、Goプログラムは `sleep` コマンドが完了するのを待たずに次の処理に進むことができます。
* `log.Printf("Waiting for command to finish...")` のように、非同期実行中に他の処理を行うことができることを示唆しています。
* `cmd.Wait()` で、開始されたコマンドの完了を明示的に待ちます。
* この例は、長時間実行される可能性のあるコマンドをバックグラウンドで実行し、後でその完了を待つ非同期実行のパターンを示しています。
5. **`ExampleCmd_StdoutPipe()`**:
* `exec.Command("echo", "-n", `{"Name": "Bob", "Age": 32}`)` を使用して、JSON文字列を標準出力に出力する `echo` コマンドを実行する `Cmd` オブジェクトを作成します。
* `stdout, err := cmd.StdoutPipe()` で、コマンドの標準出力へのパイプを取得します。このパイプは `io.Reader` インターフェースを実装しています。
* `cmd.Start()` でコマンドを開始します。`StdoutPipe` を使用する場合、`Start` を呼び出す前にパイプを取得する必要があります。
* `json.NewDecoder(stdout).Decode(&person)` を使用して、コマンドの標準出力から直接JSONデータをデコードします。これは、外部コマンドがJSON形式のデータを出力する場合に非常に強力なパターンです。
* `cmd.Wait()` でコマンドの完了を待ちます。
* この例は、外部コマンドの出力をストリームとして扱い、それをGoの他のパッケージ(この場合は `encoding/json`)と連携させる高度な入出力処理を示しています。
これらの例は、`os/exec` パッケージの柔軟性と、Goの標準ライブラリの他の部分(`bytes`, `strings`, `encoding/json`, `log` など)との連携方法を効果的に示しています。
## コアとなるコードの変更箇所
このコミットでは、`src/pkg/os/exec/example_test.go` という新しいファイルが追加されています。既存のファイルへの変更はありません。
```diff
diff --git a/src/pkg/os/exec/example_test.go b/src/pkg/os/exec/example_test.go
new file mode 100644
index 0000000000..55eaac8abc
--- /dev/null
+++ b/src/pkg/os/exec/example_test.go
@@ -0,0 +1,75 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec_test
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "log"
+ "os/exec"
+ "strings"
+)
+
+func ExampleLookPath() {
+ path, err := exec.LookPath("fortune")
+ if err != nil {
+ log.Fatal("installing fortune is in your future") // fortuneが見つからない場合のエラーハンドリング
+ }
+ fmt.Printf("fortune is available at %s\n", path) // 見つかった場合のパスの表示
+}
+
+func ExampleCommand() {
+ cmd := exec.Command("tr", "a-z", "A-Z") // 'tr' コマンドで小文字を大文字に変換
+ cmd.Stdin = strings.NewReader("some input") // 標準入力に文字列を渡す
+ var out bytes.Buffer
+ cmd.Stdout = &out // 標準出力を bytes.Buffer にリダイレクト
+ err := cmd.Run() // コマンドを実行し、完了を待つ
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("in all caps: %q\n", out.String()) // 変換された出力を表示
+}
+
+func ExampleCmd_Output() {
+ out, err := exec.Command("date").Output() // 'date' コマンドの出力を直接取得
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("The date is %s\n", out) // 取得した日付情報を表示
+}
+
+func ExampleCmd_Start() {
+ cmd := exec.Command("sleep", "5") // 'sleep 5' コマンド(5秒間待機)
+ err := cmd.Start() // コマンドを非同期で開始
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Printf("Waiting for command to finish...") // 非同期実行中に他の処理が可能
+ err = cmd.Wait() // コマンドの完了を待つ
+ log.Printf("Command finished with error: %v", err) // 完了時のエラー情報を表示
+}
+
+func ExampleCmd_StdoutPipe() {
+ cmd := exec.Command("echo", "-n", `{"Name": "Bob", "Age": 32}`) // JSON文字列を出力するコマンド
+ stdout, err := cmd.StdoutPipe() // 標準出力へのパイプを取得
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := cmd.Start(); err != nil { // コマンドを開始
+ log.Fatal(err)
+ }
+ var person struct { // JSONデコード用の構造体
+ Name string
+ Age int
+ }
+ // パイプからJSONデータを直接デコード
+ if err := json.NewDecoder(stdout).Decode(&person); err != nil {
+ log.Fatal(err)
+ }
+ if err := cmd.Wait(); err != nil { // コマンドの完了を待つ
+ log.Fatal(err)
+ }
+ fmt.Printf("%s is %d years old\n", person.Name, person.Age) // デコードしたデータを表示
+}
コアとなるコードの解説
追加された example_test.go
ファイルには、os/exec
パッケージの様々な機能を示す5つの Example
関数が含まれています。これらの関数は、Goのテストフレームワークによって自動的に実行され、その出力が期待される出力と一致するかどうかが検証されます。また、go doc
コマンドやGoの公式ドキュメントサイトで、これらのコード例がパッケージのドキュメントとして表示されます。
ExampleLookPath()
この関数は、exec.LookPath
を使用して、指定されたコマンド(この場合は fortune
)がシステムのPATH環境変数内で見つかるかどうかを確認する方法を示しています。
func ExampleLookPath() {
path, err := exec.LookPath("fortune")
if err != nil {
log.Fatal("installing fortune is in your future") // fortuneが見つからない場合のエラーハンドリング
}
fmt.Printf("fortune is available at %s\n", path) // 見つかった場合のパスの表示
}
ExampleCommand()
この関数は、exec.Command
を使用して外部コマンドを実行し、その標準入力にデータを渡し、標準出力をキャプチャする方法を示しています。
func ExampleCommand() {
cmd := exec.Command("tr", "a-z", "A-Z") // 'tr' コマンドで小文字を大文字に変換
cmd.Stdin = strings.NewReader("some input") // 標準入力に文字列を渡す
var out bytes.Buffer
cmd.Stdout = &out // 標準出力を bytes.Buffer にリダイレクト
err := cmd.Run() // コマンドを実行し、完了を待つ
if err != nil {
log.Fatal(err)
}
fmt.Printf("in all caps: %q\n", out.String()) // 変換された出力を表示
}
ExampleCmd_Output()
この関数は、Cmd.Output()
メソッドを使用して、コマンドの標準出力を直接バイトスライスとして取得する簡潔な方法を示しています。
func ExampleCmd_Output() {
out, err := exec.Command("date").Output() // 'date' コマンドの出力を直接取得
if err != nil {
log.Fatal(err)
}
fmt.Printf("The date is %s\n", out) // 取得した日付情報を表示
}
ExampleCmd_Start()
この関数は、Cmd.Start()
と Cmd.Wait()
を使用して、外部コマンドを非同期で実行し、後でその完了を待つ方法を示しています。
func ExampleCmd_Start() {
cmd := exec.Command("sleep", "5") // 'sleep 5' コマンド(5秒間待機)
err := cmd.Start() // コマンドを非同期で開始
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...") // 非同期実行中に他の処理が可能
err = cmd.Wait() // コマンドの完了を待つ
log.Printf("Command finished with error: %v", err) // 完了時のエラー情報を表示
}
ExampleCmd_StdoutPipe()
この関数は、Cmd.StdoutPipe()
を使用してコマンドの標準出力へのパイプを取得し、それを encoding/json
パッケージと組み合わせて、外部コマンドからJSONデータをストリームとして読み込む方法を示しています。
func ExampleCmd_StdoutPipe() {
cmd := exec.Command("echo", "-n", `{"Name": "Bob", "Age": 32}`) // JSON文字列を出力するコマンド
stdout, err := cmd.StdoutPipe() // 標準出力へのパイプを取得
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil { // コマンドを開始
log.Fatal(err)
}
var person struct { // JSONデコード用の構造体
Name string
Age int
}
// パイプからJSONデータを直接デコード
if err := json.NewDecoder(stdout).Decode(&person); err != nil {
log.Fatal(err)
}
if err := cmd.Wait(); err != nil { // コマンドの完了を待つ
log.Fatal(err)
}
fmt.Printf("%s is %d years old\n", person.Name, person.Age) // デコードしたデータを表示
}
これらの例は、os/exec
パッケージの基本的な使い方から、非同期実行、パイプを使ったストリーム処理、他の標準ライブラリとの連携といった、より高度な利用パターンまでを網羅しており、開発者がこのパッケージを効果的に活用するための貴重なリソースとなります。
関連リンク
- Go言語
os/exec
パッケージのドキュメント: https://pkg.go.dev/os/exec - Go言語の
Example
関数に関する公式ブログ記事 (Go 1.0.3 のリリースノートの一部): https://go.dev/doc/go1.0.3#example (このコミットが行われた時期に近い情報源) - Go言語の
Example
関数に関するより詳細な情報: https://go.dev/blog/examples
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のブログ
os/exec
パッケージのソースコードencoding/json
パッケージのドキュメントbytes
パッケージのドキュメントstrings
パッケージのドキュメントlog
パッケージのドキュメントfmt
パッケージのドキュメントtr
コマンド、date
コマンド、sleep
コマンド、echo
コマンドに関する一般的なUnix/Linuxコマンドの知識- JSONデータ形式に関する一般的な知識
- Go言語のテストとドキュメンテーションに関する一般的な知識