Linuxコマンドのパイプというのは、
コマンド1 | コマンド2
のように2つ以上のコマンドを | で繋ぎ、コマンド1の結果をコマンド2に渡して処理を続けます。
ファイルの中の特定の文字列(パターン)がある行を抽出するコマンドのgrepと、ファイルの中のテキストを並べ替えして出力するsortを使いながら、パイプの処理を見ていきましょう。
話を始める前に、下記のコマンドでファイルのサンプルを作成しておきます。
$ micro fruits.txt
orange apple grape pear peach apricot chestnut almond lemon citron
果物名の英語表記を改行区切りで並べたファイルを用意します。
最初にgrepの挙動を確認しておきます。
$ grep apple fruits.txt
grepは
grep 文字列(パターン) ファイルパス
で使用するコマンドで、今回はfruits.txtにappleという文字列があるか?という処理をしており、出力結果は
apple
になりました。
詳細は端折りますが、
$ grep '^a' fruits.txt
でfruits.txtからaから始まる文字列すべてを探すコマンドになりまして、出力結果は
apple apricot almond
になります。
※^aの詳細に触れたい時は正規表現で検索してください。
続いて、sortについて見ていきます。
$ sort fruits.txt
sort ファイルパス
でファイルの中で改行区切りで配置した文字列をアルファベット順に並び替えます。
出力内容は
almond apple apricot chestnut citron grape lemon orange peach pear
になります。
grepとsortをパイプで繋いでみます。
$ grep '^a' fruits.txt | sort
almond apple apricot
grepで得られた値をアルファベット順に並び替えられた状態で出力されました。
パイプを介し、grepで得られた結果をsortに渡して処理を行った事になります。
今回はnarabikaeというコマンドを作成しながら、パイプについて見ていくことにします。
narabikaeコマンドはホームディレクトリ(今回であれば、/home/pi/以下)で作成します。
/home/pi/narabikae.goファイルを作成して、
package main import ( "bufio" "fmt" "os" "sort" ) func main() { s := bufio.NewScanner(os.Stdin) var texts []string for s.Scan() { texts = append(texts, s.Text()) } if len(texts) > 0 { // クイックソート sort.Slice(texts, func(i, j int) bool { return texts[i] < texts[j] }) for _, text := range texts { fmt.Println(text) } } }
のコードを保存します。
今回はパスを通さず、そのまま実行します。
$ go build narabikae.go $ grep '^a' fruits.txt | ./narabikae
almond apple apricot
grepで得られた値をソートした状態で出力されました。
Goで書いたコードで、grepからパイプを介して送られてきた値は
s := bufio.NewScanner(os.Stdin) var texts []string for s.Scan() { texts = append(texts, s.Text()) }
の箇所で一行ずつtexts配列に挿入しています。
今回のnarabikaeコマンドをsortと同じようにするためには、
narabikae ファイルパス
の命令も実行できるようにする必要がありますが、今回は触れない事にします。