オフセット付きのheadコマンドを作りました
個人的な話ですが、コードやログを読むときに
$ grep -n 'fizzbuzz' fizzbuzz.rb 543: puts 'fizzbuzz'
みたいにして、該当箇所を探すということをよくします。
こうして該当行を探した後はその前後を見るためにhead
とtail
を組み合わせて
$ head -n 445 fizzbuzz.rb | tail -n 5
というような操作をするんですが、これが面倒。
head | tail
が使いにくい理由
上記のコマンドを実行すると、こんな感じの結果が得られます。
$ head -n 445 fizzbuzz.rb | tail -n 5 arr.each do |n| if n % 15 == 0 puts 'fizzbuzz' elsif n % 5 == 0 puts 'buzz'
途中で切れていて、いかにも気持ち悪いですね。
そこで、5行ではなく10行出力するように書き換えてみます。
$ head -n 450 fizzbuzz.rb | tail -n 10 arr.each do |n| if n % 15 == 0 puts 'fizzbuzz' elsif n % 5 == 0 puts 'buzz' elsif n % 3 == 0 puts 'fizz' else puts n end
10行にしても最後のend
が閉じられていませんが、問題はそこではありません。
変更前と変更後それぞれのコマンドに注目してみます。
- 変更前:
head -n 445 fizzbuzz.rb | tail -n 5
- 変更後:
head -n 450 fizzbuzz.rb | tail -n 10
5行出力するのを10行に変更したので、tail
の引数が5から10に変わっているのは良いのですが、なぜかhead
の引数まで変わっています。
出力行数を変えるだけなのに2箇所に変更を加えないといけない上、片方は一見関係なさそうなところにある。
さらに、head -n 445 fizzbuzz.rb | tail -n 5
が出力する先頭行は直感的には445-5=440なので440行目かと思いきや、441行目が先頭に来ます。
head | tail
の面倒なところまとめ
- 表示行数を変えるために2箇所に変更を加えないといけない
- しかも、変更箇所の片方はあまり関係なさそうなところにある
- n行目から表示するためには引数にn-1を指定しなければならず非直感的
tail | head
が使いにくい理由
head | tail
と同じようなことはtail | head
でも出来ますが、これも面倒です。
$ wc -l fizzbuzz.rb 987 $ tail -n 547 fizzbuzz.rb | head -n 5 $ tail -n 547 fizzbuzz.rb | head -n 10
head | tail
とは違って、変更箇所は1箇所で済んでいます。
ただ、head | tail
のときには使っていなかったwc
が必要になりますし、引数の547ってどこから来たんだよっていう感じです。
さらに、コードのようなあまり変化しないファイルであれば良いのですが、ログファイルなどは行数が随時変化するため、その度にwc
の結果を用いてtail
の引数を計算し直さなければなりません。1秒間に数百回コマンドを書き換えるだけです。簡単ですね☆
tail | head
の面倒なところまとめ
wc
を使う必要がある上、1行で完結しない987-440
のような超複雑な暗算をしなければならない- 行数が変化するファイルには事実上使用できない
やりたいこと
やりたいことをまとめると、こんな感じです。
- あるファイルのn行目からm行だけ出力したい
シンプルですね。
やりたいことは「ファイルの真ん中を出力する」だけです。
これ以上ないくらいシンプルですが、簡単には実現できませんでした*1。
ribs
というわけで、簡単なシェルスクリプトを書きました。
ファイルの先頭を取るのがhead
(頭)、末尾を取るのがtail
(尻尾)。
だったら、間を取るのはribs
(肋骨)とかで良いのでは? というネーミングです。
リンク先のREADMEにも書いてありますが、こんな感じで使います。
$ ribs -o 441 -n 5 fizzbuzz.rb arr.each do |n| if n % 15 == 0 puts 'fizzbuzz' elsif n % 5 == 0 puts 'buzz'
構文
ribs [-o offset] [-n number_of_rows] file
オプション引数
オプション | 引数 |
---|---|
o | 出力する先頭行の行番号。デフォルト値は1。 |
n | 出力する行数。デフォルト値は10。 |
さいごに
実はシェルスクリプトを真面目に書いたのは初めてです。 今まではcronに登録するやつとか、他の言語で書かれたスクリプトを叩くだけのものとか、そんな簡単なものしか書いてきませんでした。
オプション引数を設定できると自由度も上がると思うので、今後は簡単なシェルスクリプトをちょいちょい書いていきたいと思います。
あと、今回のribs
を作成するにあたり、head
, tail
, cat
あたりのオプションはひと通り調べましたが、「n行目から」というのを実現するオプションは見当たりませんでした。もし、存在するなら是非教えて下さい。