Goに入ってはGoに従え 私の好きな言葉です(スライド)。XX(架空の)という言語を書いてるならばXX言語らしく書きましょうと常々、思っております。 しかし、インフラエンジニアの魂に最も刻まれた言語は何か? それはシェルスクリプトではないですか。異論は認めます。
はじめに
なんでみんなこんなに怒っているのかというような疑問はある。世の中がぎすぎすしていて、明るい話題がない。この世にはもっと明るい話が必要だと思うのだが、思いつきませんでした。
まず、シェルスクリプトだとこう書くという明確な思考があるのにそれをGo言語で表現する方法が分からない場面で悔しい思いをしてきた方もいらっしゃるのではないかと思います。そういう方に明るい話題を提供したいです。 script はシェルスクリプトが得意とする、ファイルの読み込み、サブプロセスの実行、行数のカウント、文字列のマッチングなどを行うための Go のライブラリです。Goでシステム管理プログラムを書くのは、典型的なシェルと同じように簡単ですか? scriptはそれを簡単にすることを目的としています。大体の場合ではScripting with Go といくつかのブログを読めばよい。
script/magic.png at master · bitfield/script · GitHub より引用
シェル芸という実益を兼ねた趣味
シェル芸というおしゃれでハイソな趣味がある。シェル芸とは、マウスも使わず、ソースコードも残さず、GUIツールを立ち上げる間もなく、あらゆる調査・計算・テキスト処理をCLI端末へのコマンド入力一撃で終わらすこと。あるいはそのときのコマンド入力のこと(シェル芸の定義バージョン1.1 より引用) を指すのだかこれをやっていくのはインフラエンジニアが運用をやっていくなかで力になるものです。私も学生時代にシェル芸初心者によるシェル芸入門 というスライド をみてとてもお世話になった。こちらから演習1の問題を拝借してscript について紹介したいと思います。
演習1 という演習
先程、紹介したシェル芸初心者によるシェル芸入門というスライドには演習があります。演習1の内容は /home 以下(MACの場合には/Users)から現在ログインしているユーザーの名前を含むファイルを全て列挙してくださいというものです。それをシェルスクリプトで書くと以下のようになります。
想定回答はこちら
grep -r `whoami` /Users | grep -v matches 2>/dev/null
解く🐘
この課題をscript を用いて解決したい。と思ったのですがgrep に-r オプションがないことに気づいたのでfindfile を用いて実行する。
package main import ( "fmt" "strings" "github.com/bitfield/script" ) func main() { // whoami は用意されていないです。だが、用意されていないコマンドもexecで実行できる user, _ := script.Exec("whoami").String() // exec で実行したら実行後の改行が入るので削除しておくオプションがあるなら知りたい // filepath を作成する user_file_path := "/Users/" + remove_line_breaks(user) + "/" // 実際のコマンドを実行して標準出力に投げる _, err := script.FindFiles(user_file_path).Stdout() if err != nil { fmt.Println(err) } } // 末尾の改行を削除する func remove_line_breaks(s string) string { s = strings.TrimRight(s, "\n") if strings.HasSuffix(s, "\r") { s = strings.TrimRight(s, "\r") } return s }
権限周りで辛いが権限をめちゃくちゃにイジるとMACの場合でもいける...。
さいごに
実際の技術検証だったらscript.Exec()が具体的にどのようにシェルで実行されたりするのかを調べるのですが別に趣味なのでここで終わりです。 script を書いてて気付いたのですが別に各コマンドを実行するための近しいパッケージは存在するのでそれを調べて使えばぁッ... ここで彼のメッセージは途切れる。