しゃかまる

2014.12.16

シェル芸人への道 その1 (Advent Calendar 16日目)

こんにちは、しゃかまるです。
Advent Calendarも16日目です。進捗どうですか?私はダメです。
今回もゆるふわな記事です。

概要

シェル芸ってご存知ですか?
こんな感じのことをされている方々です。
私もCUIが好きでgitの操作は全てターミナルでやったりしてるタイプですが、シェル芸人の方々はレベルが違うなぁと感じます。

ここまで自由に文字列操作できたら楽しそうだな、と思ったので、シェル芸人さんたちを目指してGitのマージ済みブランチを検出するコマンドを書いてみました。

テーマが前と一緒じゃ…?

前回はこんな記事(Gitのマージ済みブランチ検出ツールを作った)をGoで書きました。
コンパイルしてバイナリくれ!とか言われるかと思っていたのですが、何の反響もありませんでした。
きっと、Goで書いたのでとっつきづらかったのでしょう。

ということで、前回

この程度だとシェルのワンライナーで書けるんじゃないかな、と思っています

と書いたように、シェルのワンライナーで書いてみました。
これでコピペで動かせるよ!

コマンド

最終的なコマンドは以下になります。

思っていた以上に簡単にできてしまった。。。
なお

としていますが、無駄ですね。

で同じことができるし、こっちの方が早いです。
わざわざawkにしたのはそれっぽいし使いたかったという頭の弱い理由です(・ω<)

コマンド解説

ちょっと分解して解説したいと思います。

これの解説はいらないですね。
こんな出力結果が得られます。

* develop
remotes/origin/hogehoge
remotes/origin/feature/fugafuga
remotes/origin/feature/piyopiyo
remotes/origin/feature/foobar

以下の方針でやろうと思います。

  1. カレントブランチは無視
  2. 左スペースをトリミングする (やらなくても良さそう)
  3. 出力される各行に対して、git-show コマンドを発行する

カレントブランチを無視

カレントブランチは [*]で始まります。
そのため1文字目が [*] で始まる行を除外します。

もしくは

です。

awkの詳しい文法は省きますが

のような形式で実行すると
入力の各行についてにマッチした行に対してCOMMANDを発行します。

awkって何?

横道にそれますが
awkは入力の各行に対して、特定文字で区切って取得した値に対してもろもろの操作を行うことができます。
デフォルトだと連続したwhite spaceで区切ってくれます。
個人的には、データベースの特定のテーブルに対して、カラム名のみを抜き出したい時によく使います。

例えばこんな感じの内容で、hogeというファイルを作成します。

user_id bigint(20) unsigned NOT NULL,
username varchar(255) COLLATE utf8_unicode_ci NOT NULL,
email varchar(255) COLLATE utf8_unicode_ci NOT NULL,
profile_image varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ”,

以下のコマンドを発行すると

以下のリストが抜けます。便利ですね。
バッククォートが邪魔なのでtrで消してます。

user_id
username
email
profile_image

左スペースのトリミング

前述のとおり、awkはデフォルトでwhite spaceの連続を区切りにしてくれるので勝手にやってくれます。
grepを使った場合は余計なスペースが残りますので

で消しましょう。
ブランチ名に空白は入らないのでこれで十分ですね。

ここまでで

remotes/origin/hogehoge
remotes/origin/feature/fugafuga
remotes/origin/feature/piyopiyo
remotes/origin/feature/foobar

という結果が得られます。

出力される各行に対して、git-show コマンドを発行する

ブランチ名が綺麗に抜けたので目的のコマンドを発行します。
awkで完結できないかと思っていたのですが、結局whileで回すことにしました。
発行してるコマンドを整形すると以下のようになります。

whileで1行ごとに処理します。
1行ずつ read されて 変数i として格納されます。
ブランチ名を表示するため echo $i を発行し、
git-show コマンドを発行してブランチ最終コミッターの名前とアドレスを抜きます。
前回のソースにも書きましたが、 –summary オプションを使うと create modeなどの余計な情報もついてくるので
headに渡していらない情報は除外しています。

こんな感じで目的を達成できました。

$ git branch -a –merged|awk ‘$0~/^[^\*]/ {print $1}’| while read branch; do echo $branch; git show –summary –pretty=format:’%aN (%aE)%n’ $branch |head -n 2; done

remotes/origin/hogehoge
foo (foo@example.com)

remotes/origin/feature/fugafuga
bar (bar@example.com)

remotes/origin/feature/piyopiyo
bar (bar@example.com)

remotes/origin/feature/foobar
fuga (fuga@example.com)

awkの文法の理解がいまいちだったのですが理解が進みました。
CUIを触る人なら覚えておいて損は無いと思います。

なお、タイトルには その1 と銘打ってますが、その2が来るかは分かりません。

明日は石川さんの番です。

参考サイト

http://antibayesian.hateblo.jp/entry/2014/09/15/162605
http://gauc.no-ip.org/awk-users-jp/blis.cgi/awk_fastest