読者です 読者をやめる 読者になる 読者になる

Goでechoを書いてみた

echoってshellのあれです。echoにもオプションがあって、"man echo"で


説明
echo は与えられた string をそれぞれ標準出力に書き出す。それぞれの間にはスペースを挟み、 最後の引数の後には改行を行う
。ただし -n オプションが指定されている場合は改行しない。

ほとんどのシェルには同名の組み込みコマンドがあるので、 単に `echo' として実行すると、 ここで記述されたものとは異なっ
た機能のものが実行されるだろう。

オプション
-n 行末の改行を行わない。

-e string 中の、バックスラッシュでエスケープされた文字の解釈を有効にする。


と出ます。ほぼ仕様通りに書くと次のようになるかなと思います。flagパッケージでオプションを処理していて、bufioとbytesを使って、効率的に文字を読み出します。

// echo.go
package main

import (
"bufio"
"bytes"
"flag"
"io"
"os"
)

func eval(buf *bufio.Reader) string {
s := ""
for {
c, e := buf.ReadByte()
if e == io.EOF {
break
}
if c == '\\' {
n, e := buf.ReadByte()
if e == io.EOF {
break
}
switch {
case n == 'n':
c = '\n'
case c == 'a':
c = '\a'
}
}
s += string(c)
}
return s
}

var omitNewline = flag.Bool("n", false, "don't print final newline")
var evalString = flag.Bool("e", false, "eval meta character")

func main() {
flag.Parse()
s := ""
for i := 0; i < flag.NArg(); i++ {
if i > 0 {
s += " "
}
if *evalString {
s += eval(bufio.NewReader(bytes.NewBufferString(flag.Arg(i))))
} else {
s += flag.Arg(i)
}
}
if !*omitNewline {
s += "\n"
}
os.Stdout.WriteString(s)
}


"go build echo.go"でechoができるのですが、flagパッケージだと次のようになってオプションがunix風にはできないようです。

./echo -en "abc\ncdf"
flag provided but not defined: -en
Usage of ./echo:
-e=false: eval meta character
-n=false: don't print final newline

とはいっても、-nと-eを離したら動きます(なんと--nでも--eでも動く)。

追記

opts-goは"lightweight POSIX- and GNU- style option parsing"とあるので、flagじゃなくてこっちを使うべきかもしれません。


go fix
help.go: fixed stringssplit error go1rename
opts.go:11:2: package "container/vector" has been deleted in Go 1
opts.go: fixed stringssplit

あ、vectorが消えてますね。