シェルスクリプトからid作成(GO言語を使った方法)
以前シェルスクリプトから
idを作成するものを書いたが、
csvパーサーがないとまずできないので、
結果として
pythonを使った。
ただ、pythonはこのような処理を書くのに根本的に
向かないため、GO言語で書き直すことにした。
なぜGO言語か
なぜ、簡単に使えるpython,ruby,perlでなく
いちいちビルドしないといけないコンパイル言語を使うか
というと、
$ go build pasteid
でコンパイルして、
pasteidファイルを作成して、
これをコマンドとして使う。
$ cat csvファイル(カラム名付き) | pasteid -c
と実行してほしい。
id列が追加したcsvが標準入力に描かれるはずだ。
カラム名がないcsvファイルなら下のようにする。
$ cat csvファイル(カラム名なし) | pasteid
(pasteidコマンドへのパスを通すこと。同じディレクトリにいるなら、
./pasteidでよい。)
-dオプションでデリミタを指定すること
も出来る。
今後
ソースをクリーンアップして、
csvを処理する
bash用のライブラリを
go言語で作ってgithubに公開するので
idを作成するものを書いたが、
csvパーサーがないとまずできないので、
結果として
pythonを使った。
ただ、pythonはこのような処理を書くのに根本的に
向かないため、GO言語で書き直すことにした。
なぜGO言語か
なぜ、簡単に使えるpython,ruby,perlでなく
いちいちビルドしないといけないコンパイル言語を使うか
というと、
- csvの長さ如何によってはメモリ、速度、バッファの長さを厳しい。
- 細かい制御がきかない
- そもそもスクリプト言語はコマンド等を作るのに向かない。
1−3の理由のため、C言語を使うことも考えた。
どのOSでも標準で備えているし、コンパイルさえすれば、
同じコードで動くからだ。
結局OSごとにライブラリが違うから
他のもので書いたほうが良いという人もいるかもしれない。
しかし、
C言語の標準ライブラリを見てみるとわかるが、
文字列、メモリ関係など明らかに
シェルのコマンド,デバイスファイル等を作ることを意識したものが多く、
事実BSD,Linux等OSのコマンドはほとんどC言語で描かれている。
これは、C言語はそもそもOSを作る言語であったことに由来している。
実行速度が早いからC言語を使うという人が多いが、
それは
OSを作りたい→ある程度の速度が必要→C言語
という
OSを作りたい→ある程度の速度が必要→C言語
という
結果として早い言語であるC言語を選択した点を忘れている。
じゃあC言語でかけば良いじゃないか
というかもしれないが、
C言語で書こうとすると
csvパーサーが標準ライブラリにないので
作業効率が悪い。
(C言語の標準ライブラリにあるものなら、
GO言語で書くよりC言語で書いたほうが、
言語の安定性、マルチプラットフォームという意味でよい。
また、作業効率でもそんなに変わらないはず。)
また、Windowsで実行することを考えると、
また、Windowsで実行することを考えると、
VisualC++等は最近あまり動きがない上、
C#,Powershellの方にMS
が興味がある。
また、VisuallC++をやろうとすると
また、VisuallC++をやろうとすると
どうしてもVisual studioをインストールする必要が出る。
Windowsで
C言語を使うなら、
wslのbashでgccを使うのがよい。
そこで、csvパーサーを持っていて、
C言語の役割を置き換えることを目指している
Go言語を使うことにする。
Go言語はC言語よりもコミュニティという意味でも安定している。
(C言語はおそらくQtにコミュニティが集中しているが、
QtはフリーのものはGPLライセンス。
TrueOSに使われている部分等BSDライセンスの部分もあるらしいが...
GO言語も一部GPLライセンスらしいので注意すること
http://sssslide.com/speakerdeck.com/nabeken/go-and-license
)
前回の結構苦労した
csvのid列の追加をgo言語だと下のように
かける
package main
import (
"encoding/csv"
"flag"
"fmt"
"io"
"os"
"strconv"
"strings"
)
//ls -1 | xargs ls -1 | sed 's/:$/\//' | ./conbertfrom_csv/convertfrom_csv
var (
icm = flag.Bool("c", false, "help message for b option")
delimiter = flag.String("d", ",", "help message for d option")
)
//文字列の途中でカラムを改行する場合は、"""をつけること。でないと正しく動かない。
//ls -1 | xargs ls -1 | ./conbertfrom_csv/convertfrom_csv
//deli=$(echo -e "\t")
//cat staff.1.csv | go run convertfrom_csv.go -c -d "${deli}"
//全くからの行は無視するように作っている。
func main() {
//これがないとオプション引数が展開されないので注意。
flag.Parse()
var err error
//ひとつの行のカラムの長さも考える必要があるかも。
var row []string
//csvのデリ見たが指定できていないのであとでしてい。
//csvを読み込むために必要
cin := csv.NewReader(os.Stdin)
//CSV.Commaもデリミタは1バイトで決め打ちしている。ためこれでよい。
//string[0]で勝手にbyteにキャストされるので後で変換する必要がある。
deli := (*delimiter)[0]
//runeで入れる必要がある。runeもstringもバイト列のためこのようなことができる。
cin.Comma = rune(deli)
//forの三項目はfor文の最初に評価されるのでここでも一度読んでおく。
row, err = cin.Read()
//ストリームの最後まで読んだら、ENDになる。
for i := 0; err != io.EOF; row, err = cin.Read() {
//EOF意外のエラーだった場合は標準エラー出力に吐き出す。
if err != io.EOF && err != nil {
fmt.Fprintln(os.Stderr, "CSV形式のデータを正しく読み取れませんでした。")
os.Exit(1)
//もしくは下で処理をやめてシェル自体を継続させる。
//fmt.Fprintln(os.Stderr, "正しく読み取れなかった可能性があるデータがあります。")
//break;
}
//id列の追加部分ここだけユニーク
if i == 0 && *icm {
fmt.Print("id" + string(deli))
} else if i != 0 && *icm {
fmt.Print(strconv.Itoa(i) + string(deli))
} else {
fmt.Print(strconv.Itoa(i+1) + string(deli))
}
//csv形式の行をjoinでまとめている。
fmt.Println(strings.Join(row, string(deli)))
i++
}
}
$ go build pasteid
でコンパイルして、
pasteidファイルを作成して、
これをコマンドとして使う。
$ cat csvファイル(カラム名付き) | pasteid -c
と実行してほしい。
id列が追加したcsvが標準入力に描かれるはずだ。
カラム名がないcsvファイルなら下のようにする。
$ cat csvファイル(カラム名なし) | pasteid
(pasteidコマンドへのパスを通すこと。同じディレクトリにいるなら、
./pasteidでよい。)
-dオプションでデリミタを指定すること
も出来る。
今後
ソースをクリーンアップして、
csvを処理する
bash用のライブラリを
go言語で作ってgithubに公開するので
興味がある人はぜひ見てほしい。
コメント
コメントを投稿