LoginSignup
13
20

More than 5 years have passed since last update.

goで簡単なコマンドラインツールを書くためのメモ (コマンド引数パース,外部コマンド実行,正規表現,APIリクエスト,jsonパース,xmlパース)

Last updated at Posted at 2017-03-18

go初心者なので、こうした方がいいなどガンガンフィードバックいただきたいです。

コマンドの引数を取得する

固定の引数はflag.Arg(0)で取得、オプションのコマンドはflag.Int()などから取得
引数が必須なときはlen(flag.Args())でチェック

go run command_argument.go --count=3 hello 
hello
hello
hello
package main

import (
    "flag"
    "fmt"
)

func main() {
    count := flag.Int("count", 1, "count is int")
    flag.Parse()
    if len(flag.Args()) < 1 {
        fmt.Println("need argument")
        return
    }

    for i := 0; i < *count; i++ {
        fmt.Println(flag.Arg(0))
    }
}

コマンドの実行

ls -lの実行して表示

package main

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

func main() {
    output, err := exec.Command("ls", "-la").Output()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    println(string(output))
}

http://qiita.com/tanksuzuki/items/9205ff70c57c4c03b5e5 より

正規表現

公式に素晴らしい例があったので、、それを持ってきました
https://gobyexample.com/regular-expressions

package main

import (
    "regexp"
    "fmt"
    "bytes"
)

// https://gobyexample.com/regular-expressions
func main() {

    // 簡単に含まれるか確認
    match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
    fmt.Println(match) // true

    // パターン作成
    r, _ := regexp.Compile("p([a-z]+)ch")

    // パターンが含まれるか
    fmt.Println(r.MatchString("peach")) // true

    // パターンを検索
    fmt.Println(r.FindString("peach punch")) // peach

    // パターンを検索して、その文字のインデックスを取得
    fmt.Println(r.FindStringIndex("peach punch")) // [0 5]

    // 最初にヒットしたものと、中のグループを取り出す
    fmt.Println(r.FindStringSubmatch("peach punch")) // [peach ea]

    // Similarly this will return information about the
    // indexes of matches and submatches.
    fmt.Println(r.FindStringSubmatchIndex("peach punch")) // [0 5 1 3]

    // The `All` variants of these functions apply to all
    // matches in the input, not just the first. For
    // example to find all matches for a regexp.
    fmt.Println(r.FindAllString("peach punch pinch", -1)) // [peach punch pinch]

    // These `All` variants are available for the other
    // functions we saw above as well.
    fmt.Println(r.FindAllStringSubmatchIndex( // [[0 5 1 3] [6 11 7 9] [12 17 13 15]]
        "peach punch pinch", -1))

    // Providing a non-negative integer as the second
    // argument to these functions will limit the number
    // of matches.
    fmt.Println(r.FindAllString("peach punch pinch", 2)) // [peach punch]

    // Our examples above had string arguments and used
    // names like `MatchString`. We can also provide
    // `[]byte` arguments and drop `String` from the
    // function name.
    fmt.Println(r.Match([]byte("peach"))) // true

    // When creating constants with regular expressions
    // you can use the `MustCompile` variation of
    // `Compile`. A plain `Compile` won't work for
    // constants because it has 2 return values.
    r = regexp.MustCompile("p([a-z]+)ch")
    fmt.Println(r) // p([a-z]+)ch

    // The `regexp` package can also be used to replace
    // subsets of strings with other values.
    fmt.Println(r.ReplaceAllString("a peach", "<fruit>")) // a <fruit>

    // The `Func` variant allows you to transform matched
    // text with a given function.
    in := []byte("a peach")
    out := r.ReplaceAllFunc(in, bytes.ToUpper)
    fmt.Println(string(out)) // a PEACH
}

API アクセスして、JSONの要素にアクセスする

リクエストにnet/httpを使い、レスポンスの取得にioutil.ReadAll()を使い、レスポンスをオブジェクトに変換をjson.Unmarshal()でする感じです。

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
)

type Route struct {
    Summary string `json:"summary"`
}
type Response struct {
    Routes []Route `json:"routes"`
}

func main() {
    body := request()
    fmt.Println(string(body))

    response := new(Response)
    if err := json.Unmarshal(body, &response); err != nil {
        log.Println("JSON Unmarshal error:", err)
        return
    }
    fmt.Println(string(response.Routes[0].Summary))
}
func request() []byte {
    client := &http.Client{}
        // クエリを加工しない場合はhttp.Getで十分っぽい
    req, err := http.NewRequest("GET", "http://maps.googleapis.com/maps/api/directions/json",
        nil)
    if err != nil {
        log.Print(err)
        os.Exit(1)
    }
    q := req.URL.Query()
    q.Add("origin", "tokyo")
    q.Add("destination", "osaka")
    req.URL.RawQuery = q.Encode()
    resp, err := client.Do(req)
    if err != nil {
        log.Print("Request error:", err)
        os.Exit(1)
    }
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    return body
}

これで こういう感じで表示されます

{
...
   "routes" : [
      {
...
         "summary" : "新東名高速道路",
 }
   ],
   "status" : "OK"
}
新東名高速道路

API アクセスして、XMLの要素にアクセスする

ほぼ同じ、jsonがxmlになってencoding/xmlを使うようになったのみです

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "encoding/xml"
)

type Route struct {
    Summary string `xml:"summary"`
}
type Response struct {
    Routes Route `xml:"route"`
}

func main() {
    body := request()
    fmt.Println(string(body))

    response := new(Response)
    if err := xml.Unmarshal(body, &response); err != nil {
        log.Println("JSON Unmarshal error:", err)
        return
    }
    fmt.Println(string(response.Routes.Summary))
}
func request() []byte {
    client := &http.Client{}
    req, err := http.NewRequest("GET", "http://maps.googleapis.com/maps/api/directions/xml",
        nil)
    if err != nil {
        log.Print(err)
        os.Exit(1)
    }
    q := req.URL.Query()
    q.Add("origin", "tokyo")
    q.Add("destination", "osaka")
    req.URL.RawQuery = q.Encode()
    resp, err := client.Do(req)
    if err != nil {
        log.Print("Request error:", err)
        os.Exit(1)
    }
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    return body
}
13
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
20