Goの外部コマンド実行方法のまとめ

プログラミング

プログラムからOSのコマンドを実行することによって、プログラムでは複雑になってしまう処理を簡単に行うことが出来ることもあります。

多くのプログラミング言語には、外部コマンドを実行するための機能が備わっています。

本記事では、Go言語のコマンド実行について解説します。

記事内に記載しているプログラムは、Go1.15.2を使って動作確認をしています。

Goの外部コマンド実行方法のまとめ

Goのコマンド実行について、以下の内容を解説します。

  • コマンド実行を行うパッケージ
  • 様々なコマンド実行の方法
  • コマンド実行に標準入力を渡す方法
  • コマンド実行の補助機能

コマンド実行を行うパッケージ

Goでコマンド実行を行うには、os/execパッケージを使用します。
プログラム内でのインポートが必要になります。

import (
    "os/exec"
)

実行したいコマンドをexec.Commandの引数に指定します。
第1引数にコマンド本体、第2引数以降にオプションを指定します。

実行の仕方や結果の受取り方によって、様々な実行方法が用意されていますので以下で紹介していきます。

様々なコマンド実行の方法

コマンドの実行方法について、結果を受取りやコマンドの終了を待つかどうかなどにより、様々な実行方法があります。

結果を取得しない実行方法(Run)

コマンドの実行後に終了するまで待ち、結果を受け取らない場合は、Runを使用します。

err := exec.Command("sleep", "1").Run()

コマンドの実行に失敗した場合は、エラーを返します。
上記のプログラムでは、1秒間のsleepコマンドを実行し、終了するまで待ちます。

結果を取得する実行方法(Output)

コマンドの実行後に終了するまで待ち、結果を受け取る場合は、Outputを使用します。

result, err := exec.Command("date").Output()
fmt.Println(string(result)) // -> 2021年  1月  8日 金曜日 10:38:40 JST

1つ目の戻り値にコマンドの実行結果がbyte配列で入ります。
文字列として出力するには、文字列型としてキャストします。

完了を待たない実行方法(Start)

コマンドの実行後に終了を待たず、次の処理を実行する場合は、Startを使用します。

err = exec.Command("sleep", "5").Start()

コマンドの実行に失敗した場合は、エラーを返します。
上記のプログラムでは、5秒間のsleepコマンドを実行していますが、終了を待たないのでプログラムとしては意味のない処理になります。
実行したらずっと起動し続けるデーモンの起動や、実行時間の長い処理を非同期で行う場合などには有用です。

実行後に完了を待ち合わせる方法(Wait)

コマンドの実行後に何らかの処理を行って、必要なときに待合せをする場合は、Waitを使用します。

cmd := exec.Command("sleep", "5")
cmd.Start()
cmd.Wait()

上記のプログラムでは、Startでコマンドを開始して、Waitで待合せを行っていますが、その間に任意の処理を行うことができます。
コマンドの待ち時間に他の処理を効率よく進めたい場合などには有用です。

標準エラー出力も受け取る方法(CombinedOutput)

これまでの方法は、実行に失敗するとエラーを受け取れましたが、標準エラーに出力されている内容までは受け取れていませんでした。
OSのコマンドが標準エラー出力に対して出力する情報も受け取るには、CombinedOutputを使います。

result, err = exec.Command("ls", "not exists file").CombinedOutput()
if err != nil {
    fmt.Println(err) // -> exit status 2
}
fmt.Println(string(result)) // -> ls: not exists file にアクセスできません: そのようなファイルやディレクトリはありません

上記のプログラムでは、エラーが発生した場合は、errの情報を表示しつつ、標準エラー出力の内容をresultに受け取って表示しています。

コマンド実行に標準入力を渡す方法

コマンドの実行に標準入力を渡して、プログラムから情報を入力させたい場合は、StdinPipeを使います。
コマンドで特殊な文字となる”<“などを入力として使いたい場合などに有用です。

cmd = exec.Command("cat")
stdin, err := cmd.StdinPipe()
io.WriteString(stdin, "test")
stdin.Close()
result, err = cmd.Output()
fmt.Println(string(result)) // -> test

コマンド実行の補助機能

コマンド実行時に役立つ補助機能を紹介します。

プロセスIDの取得方法

実行しているコマンドのプロセスIDを取得するには、Process.Pidを使います。

cmd = exec.Command("sleep", "5")
cmd.Start()
fmt.Println(cmd.Process.Pid) // -> 27036

コマンドの強制終了方法

実行しているコマンドを強制終了(kill)するには、Killを使います。

cmd = exec.Command("sleep", "5")
cmd.Start()
cmd.Process.Kill()

コマンドのパスを確認する方法

実行するコマンドのパスを確認するには、LookPathを使います。

path, err := exec.LookPath("go")
fmt.Println(path) // -> /usr/local/go/bin/go

まとめ

Goのコマンド実行についてまとめると、以下となります。

  • GoからOSコマンドを実行するには、os/execパッケージを使用する。
  • 結果の受取りや終了の待機などのパターンにより様々な実行方法が提供されている。
  • 標準入力や標準出力の情報の受け渡しもできる。

マルチOSで使用するアプリケーションの場合は、コマンドの違いを考慮する必要があります。
また、コマンドインジェクション等の脆弱性にも注意が必要です。

ですが、OSコマンドを利用することで、プログラムで実現できる範囲が広がるので、必要な場合には使ってみてはいかがでしょうか。

 

今回は、Goのコマンド実行について解説しました。

以上、参考になれば幸いです。

コメント

タイトルとURLをコピーしました