CLIチュートリアルに移動:フォーチュンクローン

ビルドする2つのCLIアプリチュートリアルを作成しましたgololcatそしてgocowsay。両方で私は使用しましたfortune入力ジェネレータとして。

この記事では、パイプの三部作を次のように完成させます。gofortune

とはフォーチュン、 最初?ウィキペディアが言うように、Fortuneは、引用のデータベースからの疑似ランダムメッセージを表示する単純なプログラムです。

基本的に、ランダムクォートジェネレータ。

Unixバージョン7(1979)にまでさかのぼる非常に長い歴史があります。それはまだ強くなっています。多くのLinuxディストリビューションはそれをプレインストールし、OSXでは次を使用してインストールできますbrew install fortune

一部のシステムでは、シェルを使用するときに挨拶または別れのメッセージとして使用されます。

ウィキペディアも言います

多くの人々は幸運をカウセイコマンド、ダイアログにユーモアを追加します。

それは私です!私が使う以外はgocowsayコマンド。

イントロで十分、Goでフォーチュンクローンを作成しましょう

これが私たちのプログラムが行うことの内訳です。

fortunesフォルダーの場所は、システムとディストリビューションによって異なり、ビルドフラグです。ハードコーディングすることも環境変数を使用することもできますが、演習として、汚いことをして尋ねますfortune直接、-f出力するフラグ:

出力の最初の行には、fortunesフォルダーのパスが含まれています。

package main

import ( “fmt” “os/exec” )

func main() { out, err := exec.Command(“fortune”, “-f”).CombinedOutput() if err != nil { panic(err) }

<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(string(<span style="color:#a6e22e">out</span>))

}

このスニペットは、私が取得したとおりに出力を複製します。のようだfortune -f出力をstderrに書き込むので、私はCombinedOutput、両方を取得するにはstdoutそしてstderr

しかし、私は最初の行が欲しいだけです。どうやるか?これにより、のすべての出力が出力されます。stderr1行ずつ:

package main

import ( “bufio” “fmt” “os/exec” )

func main() { fortuneCommand := exec.Command(“fortune”, “-f”) pipe, err := fortuneCommand.StderrPipe() if err != nil { panic(err) } for outputStream.Scan() { fmt.Println(outputStream.Text()) } }

最初の行だけを取得するには、forループを削除し、最初の行をスキャンします。

package main

import ( “bufio” “fmt” “os/exec” )

func main() { fortuneCommand := exec.Command(“fortune”, “-f”) pipe, err := fortuneCommand.StderrPipe() if err != nil { panic(err) } fortuneCommand.Start() outputStream := bufio.NewScanner(pipe) outputStream.Scan() fmt.Println(outputStream.Text()) }

それでは、その行を選択してパスを抽出しましょう。

私のシステムでは、出力の最初の行は100.00% /usr/local/Cellar/fortune/9708/share/games/fortunes。最初の出現から始まる部分文字列を作成しましょう/char:

line := outputStream.Text()
path := line[strings.Index(line, "/"):]

今、私は運命の道を歩んでいます。そこにあるファイルにインデックスを付けることができます。がある.datバイナリファイル、およびプレーンテキストファイル。バイナリファイルを破棄します。off/攻撃的な運命を含むフォルダ全体。

まず、ファイルにインデックスを付けましょう。私はpath/filepathパッケージWalkから始まるファイルツリーを反復するメソッドroot。代わりに使用しますioutil.ReadDir()運命のフォルダがネストされている可能性があるためです。の中にWalkFunc visitを使用して.datファイルを破棄しますfilepath.Ext()、フォルダファイルを破棄します(例:/off、ただしサブフォルダー内のファイルではありません)およびすべての攻撃的な財産。/off、および残りの各ファイルの値を出力します。

func visit(path string, f os.FileInfo, err error) error {
	if strings.Contains(path, "/off/") {
		return nil
	}
	if filepath.Ext(path) == ".dat" {
		return nil
	}
	if f.IsDir() {
		return nil
	}
	files = append(files, path)
	return nil
}

func main() { fortuneCommand := exec.Command(“fortune”, “-f”) pipe, err := fortuneCommand.StderrPipe() if err != nil { panic(err) } fortuneCommand.Start() outputStream := bufio.NewScanner(pipe) outputStream.Scan() line := outputStream.Text() root := line[strings.Index(line, “/”):]

<span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Walk</span>(<span style="color:#a6e22e">root</span>, <span style="color:#a6e22e">visit</span>)
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
	panic(<span style="color:#a6e22e">err</span>)
}

}

これらの値をスライスに入れて、後でランダムな値を選択できるようにします。files文字列のスライスと私はそれに追加しますvisit()関数。の終わりにmain()取得したファイルの数を印刷します。

package main

import ( “bufio” “log” “os” “os/exec” “path/filepath” “strings” )

var files []string

func visit(path string, f os.FileInfo, err error) error { if err != nil { log.Fatal(err) } if strings.Contains(path, “/off/”) { return nil } if filepath.Ext(path) == “.dat” { return nil } if f.IsDir() { return nil } files = append(files, path) return nil }

func main() { fortuneCommand := exec.Command(“fortune”, “-f”) pipe, err := fortuneCommand.StderrPipe() if err != nil { panic(err) } fortuneCommand.Start() outputStream := bufio.NewScanner(pipe) outputStream.Scan() line := outputStream.Text() root := line[strings.Index(line, “/”):]

<span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Walk</span>(<span style="color:#a6e22e">root</span>, <span style="color:#a6e22e">visit</span>)
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
	panic(<span style="color:#a6e22e">err</span>)
}

println(len(<span style="color:#a6e22e">files</span>))

}

私は今使用します乱数ジェネレーターに移動配列からランダムなアイテムを選択する機能:

// Returns an int >= min, < max
func randomInt(min, max int) int {
	return min + rand.Intn(max-min)
}

func main() {

<span style="color:#75715e">//...

rand.Seed(time.Now().UnixNano()) i := randomInt(1, len(files)) randomFile := files[i] println(randomFile) }

私たちのプログラムは、実行のたびにランダムなフォーチュンファイル名を出力するようになりました。

私が今見逃しているのは、ファイル内の運勢をスキャンし、ランダムに印刷することです。各ファイルでは、引用符は%一人で一列に並んでいます。このパターンを簡単に検出して、配列内のすべての引用符をスキャンできます。

file, err := os.Open(randomFile)
if err != nil {
    panic(err)
}
defer file.Close()

b, err := ioutil.ReadAll(file) if err != nil { panic(err) }

quotes := string(b)

quotesSlice := strings.Split(quotes, “%”) j := randomInt(1, len(quotesSlice))

fmt.Print(quotesSlice[j])

フォーチュンファイル全体をスライスでスキャンしてからランダムなアイテムを選択するため、これは実際には効率的ではありませんが、機能します。

だから、これが私たちの非常に基本的なものの最終バージョンですfortuneクローン。それはオリジナルの多くを逃しますfortuneコマンドですが、それは始まりです。

package main

import ( “bufio” “fmt” “io/ioutil” “log” “math/rand” “os” “os/exec” “path/filepath” “strings” “time” )

var files []string

// Returns an int >= min, < max func randomInt(min, max int) int { return min + rand.Intn(max-min) }

func visit(path string, f os.FileInfo, err error) error { if err != nil { log.Fatal(err) } if strings.Contains(path, “/off/”) { return nil } if filepath.Ext(path) == “.dat” { return nil } if f.IsDir() { return nil } files = append(files, path) return nil }

func main() { fortuneCommand := exec.Command(“fortune”, “-f”) pipe, err := fortuneCommand.StderrPipe() if err != nil { panic(err) } fortuneCommand.Start() outputStream := bufio.NewScanner(pipe) outputStream.Scan() line := outputStream.Text() root := line[strings.Index(line, “/”):]

<span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Walk</span>(<span style="color:#a6e22e">root</span>, <span style="color:#a6e22e">visit</span>)
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
	panic(<span style="color:#a6e22e">err</span>)
}

<span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">Seed</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">UnixNano</span>())
<span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">randomInt</span>(<span style="color:#ae81ff">1</span>, len(<span style="color:#a6e22e">files</span>))
<span style="color:#a6e22e">randomFile</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">files</span>[<span style="color:#a6e22e">i</span>]

<span style="color:#a6e22e">file</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Open</span>(<span style="color:#a6e22e">randomFile</span>)
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
	panic(<span style="color:#a6e22e">err</span>)
}
<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">file</span>.<span style="color:#a6e22e">Close</span>()

<span style="color:#a6e22e">b</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadAll</span>(<span style="color:#a6e22e">file</span>)
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
	panic(<span style="color:#a6e22e">err</span>)
}

<span style="color:#a6e22e">quotes</span> <span style="color:#f92672">:=</span> string(<span style="color:#a6e22e">b</span>)

<span style="color:#a6e22e">quotesSlice</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Split</span>(<span style="color:#a6e22e">quotes</span>, <span style="color:#e6db74">"%"</span>)
<span style="color:#a6e22e">j</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">randomInt</span>(<span style="color:#ae81ff">1</span>, len(<span style="color:#a6e22e">quotesSlice</span>))

<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Print</span>(<span style="color:#a6e22e">quotesSlice</span>[<span style="color:#a6e22e">j</span>])

}

まとめて、私は移動しますvisitのインライン関数引数としてfilepath.Walk移動しますfiles内部のローカル変数になるmain()グローバルファイル変数の代わりに:

package main

import ( “bufio” “fmt” “io/ioutil” “log” “math/rand” “os” “os/exec” “path/filepath” “strings” “time” )

// Returns an int >= min, < max func randomInt(min, max int) int { return min + rand.Intn(max-min) }

func main() { var files []string

<span style="color:#a6e22e">fortuneCommand</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#e6db74">"fortune"</span>, <span style="color:#e6db74">"-f"</span>)
<span style="color:#a6e22e">pipe</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fortuneCommand</span>.<span style="color:#a6e22e">StderrPipe</span>()
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
	panic(<span style="color:#a6e22e">err</span>)
}
<span style="color:#a6e22e">fortuneCommand</span>.<span style="color:#a6e22e">Start</span>()
<span style="color:#a6e22e">outputStream</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">bufio</span>.<span style="color:#a6e22e">NewScanner</span>(<span style="color:#a6e22e">pipe</span>)
<span style="color:#a6e22e">outputStream</span>.<span style="color:#a6e22e">Scan</span>()
<span style="color:#a6e22e">line</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">outputStream</span>.<span style="color:#a6e22e">Text</span>()
<span style="color:#a6e22e">root</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">line</span>[<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Index</span>(<span style="color:#a6e22e">line</span>, <span style="color:#e6db74">"/"</span>):]

<span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Walk</span>(<span style="color:#a6e22e">root</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">path</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">f</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">FileInfo</span>, <span style="color:#a6e22e">err</span> <span style="color:#66d9ef">error</span>) <span style="color:#66d9ef">error</span> {
    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
        <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>)
    }
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">path</span>, <span style="color:#e6db74">"/off/"</span>) {
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
	}
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Ext</span>(<span style="color:#a6e22e">path</span>) <span style="color:#f92672">==</span> <span style="color:#e6db74">".dat"</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
	}
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">f</span>.<span style="color:#a6e22e">IsDir</span>() {
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
	}
	<span style="color:#a6e22e">files</span> = append(<span style="color:#a6e22e">files</span>, <span style="color:#a6e22e">path</span>)
	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
})
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
	panic(<span style="color:#a6e22e">err</span>)
}

<span style="color:#a6e22e">rand</span>.<span style="color:#a6e22e">Seed</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">UnixNano</span>())
<span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">randomInt</span>(<span style="color:#ae81ff">1</span>, len(<span style="color:#a6e22e">files</span>))
<span style="color:#a6e22e">randomFile</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">files</span>[<span style="color:#a6e22e">i</span>]

<span style="color:#a6e22e">file</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Open</span>(<span style="color:#a6e22e">randomFile</span>)
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
	panic(<span style="color:#a6e22e">err</span>)
}
<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">file</span>.<span style="color:#a6e22e">Close</span>()

<span style="color:#a6e22e">b</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadAll</span>(<span style="color:#a6e22e">file</span>)
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
	panic(<span style="color:#a6e22e">err</span>)
}

<span style="color:#a6e22e">quotes</span> <span style="color:#f92672">:=</span> string(<span style="color:#a6e22e">b</span>)

<span style="color:#a6e22e">quotesSlice</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Split</span>(<span style="color:#a6e22e">quotes</span>, <span style="color:#e6db74">"%"</span>)
<span style="color:#a6e22e">j</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">randomInt</span>(<span style="color:#ae81ff">1</span>, len(<span style="color:#a6e22e">quotesSlice</span>))

<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Print</span>(<span style="color:#a6e22e">quotesSlice</span>[<span style="color:#a6e22e">j</span>])

}

今はできるよgo build; go installと三部作gofortune gocowsayそしてgololcat完成されました:


その他のチュートリアル: