PHPerだが今日初めてGo言語に手を出してみる試み


# この試みのゴール

* Go言語でコマンドを叩けるようになる

# つまづいたときのググり方

`go` だけでググるとGo言語以外の情報も出てくるので「Go言語」や「go lang」で検索する。

# Goをインストールする

Macで作ってLinuxにデプロイしようと思うので、Mac, Linux, Windowsにコンパイルできるように、クロスコンパイル可能な状態でGoをインストールする:

```shell
brew install go --cross-compile-common
```

# とりあえず Hello World

適当にフォルダ作って…

```shell
cd ~/Desktop
mkdir my-first-go
cd my-first-go
```

そこにgoのファイル作って…

```shell
touch hello-world.go
```

エディタでそれを開いて、以下の10行程度のコードを書く。

```go:hello-world.go
package main

import (
	"fmt"
)

func main() {
	fmt.Print("Hello World\n")
}
```

おもむろに実行してみる

```shell
go run hello-world.go
```

Hello Worldって出ればOK。

# コンパイルしてみよう

`go build` ってやるだけでコンパイルできる

```shell
go build hello-world.go
```

ビルドしたファイルを実行してみる:

```shell
% ./hello-world
Hello World
```

こんな簡単にバイナリのコマンドが作れるなんてワクワクする！

# さらに、Linux 64ビット用のバイナリを作ってみる

Mac用の `hello-world` は消して、

```shell
rm -f hello-world
```

Linux 64ビット用のバイナリを作る:

```shell
GOOS=linux GOARCH=amd64 go build hello-world.go
```

できたら、適当なLinuxのマシンに送って、

```shell
scp hello-world sakura-vps:
```

Linuxにログインして、

```shell
ssh sakura-vps
```

実行してみる:

```shell
$ ./hello-world
Hello World
```

おー、出た！

Linuxからログアウトする

```shell
exit
```

# コマンドを実行するだけのプログラムを作ってみる

とりあえず、Linuxコマンドさえコールできれば、Go言語でひかかってもなんとかなりそうなので、コマンドの呼び出し方を覚える。

`hello-world.go` をコピーして `call-command.go` を作る

```shell
cp hello-world.go call-command.go
```

コマンドを実行するには [exec] パッケージをインポートする:

```go
import (
	"fmt"
	"os/exec"
)
```

あと、`fmt.Print` もいいけど、 `log` パッケージの `log.Print` のほうが時刻も一緒に出力してくれるので、`fmt` を `log` に置き換える:

```go
import (
	"log"
	"os/exec"
)
```

`date` コマンドを実行するコードを書く:

```go:call-command.go
package main

import (
	"log"
	"os/exec"
)

func main() {
	log.Print("これはコマンドを実行するプログラムです!\n")
	out, error := exec.Command("date").Output()

	if error != nil {
		log.Printf("エラー: %s", error)
		return
	}

	log.Printf("現在時刻: %s", out)
}
```

実行してみる:

```
% go run call-command.go                                                                                                                                                                                                           [18:23:40]
2013/12/04 18:24:24 これはコマンドを実行するプログラムです!
2013/12/04 18:24:24 現在時刻: Wed Dec  4 18:24:24 JST 2013
```

ちゃんと、現在時刻出ました!

エラーの場合どうなるか試してみる。
手っ取り早く `date` コマンドを `false` コマンドに置き換えてみる:


```go
    out, error := exec.Command("false").Output()
                                ~~~~~ ここ
```

実行してみる:

```
% go run call-command.go                                                                                                                                                                                                           [18:24:34]
2013/12/04 18:26:44 これはコマンドを実行するプログラムです!
2013/12/04 18:26:44 エラー: exit status 1
```

ちゃんとエラーの分岐に入りました!

## 引数を取るコマンドの実行

`ls -la` のように引数をとるコマンドを試してみる。
コマンドの引数は `exec.Command()` の第二引数以降に与える。

```go:call-command.go
package main

import (
	"log"
	"os/exec"
)

func main() {
	log.Print("これはコマンドを実行するプログラムです!\n")
	out, error := exec.Command("ls", "-la").Output()

	if error != nil {
		log.Printf("エラー: %s", error)
		return
	}

	log.Printf("%s", out)
}
```

実行してみる:

```
% go run call-command.go                                                                                                                                                                                                           [18:29:46]
2013/12/04 18:30:58 これはコマンドを実行するプログラムです!
2013/12/04 18:30:58 total 4424
drwxr-xr-x   5 suin  staff      170 Dec  4 18:08 .
drwx------+ 16 suin  staff      544 Dec  4 17:59 ..
-rw-r--r--   1 suin  staff      278 Dec  4 18:29 call-command.go
-rwxr-xr-x   1 suin  staff  2255544 Dec  4 18:08 hello-world
-rw-r--r--   1 suin  staff       77 Dec  4 18:02 hello-world.go
```

## 時間のかかるコマンド

時間がかかるコマンドは、終わるのを待たずに処理を進めたい場合があるので、そのやり方を覚える。

以下は、`sleep 2` コマンドを実行する例:

```go
package main

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

func main() {
	log.Print("これはコマンドを実行するプログラムです!\n")
	command := exec.Command("sleep", "2")
	error := command.Start()

	if error != nil {
		panic(fmt.Sprintf("エラー1: %v", error)) // コマンドがなかった場合とか
	}

	log.Print("コマンドを開始しました")

	error = command.Wait()

	if error != nil {
		panic(fmt.Sprintf("エラー2: %v", error)) // コマンドがエラーステータスで終了した場合
	}

	log.Print("コマンドが終了しました")
}

```


こんなかんじで、大まかなコマンドの実行方法がつかめたと思う。




[exec]: http://golang.org/pkg/os/exec/