Lambdaカクテル

京都在住Webエンジニアの日記です

標準出力をフィルタ・変形する強力なパイプ: teip使ってみた

最近teipというツールをはてブで知った。説明を読んでいるとなかなか面白いしなんかに使えそうだなという印象を受けたので使ってみた。

speakerdeck.com

github.com

teipとは

ひとことでは正確な表現をしにくいが,「フィールドやバイトオフセット,正規表現で変形できるパイプ」である。

通常のUNIXのパイプは「他のコマンドのstdoutを受け取り,別のコマンドを起動してそのstdioにぜんぶ流し込む」機能だ。だがその「ぜんぶ流し込む」箇所を「特定の箇所だけ流し込む」にできたら?というのをこのツールがやってしまった。

いやいや「特定の箇所だけ流し込む」だけならgrepやsedでもできる。このコマンドがすごいのは,「特定の箇所だけ流し込む」だけではなく,「流し込んで得られたstdoutを元のstdioに合成して」返してくれるからだ。

例えば以下のような入力を与える。-f 3,4としているのはcut-fと互換の記法で,空白区切りのフィールドのうち3と4を選ぶというフィルタだ。

$ echo 'foo bar buzz piyo hoge fuga' | teip -f 3,4 -- sed -e 's/^./\U&/g'
foo bar Buzz Piyo hoge fuga

stdinのうち3・4番フィールドがsed -e 's/^./\U&/gに行毎になって渡され,その結果が元の入力に格納されてstdoutに吐き出された。

f:id:Windymelt:20200702001707p:plain
フィルタに沿ってstdinがパイプされ,元の位置に格納される

teipお得ポイント

そんなのperl/awk/shell scriptでできるよということもできるが,perl/awk/shell scriptに頼ることで発生する記述性・パフォーマンス上の問題に立ち向かっている。

  • perlでやろうとすると抽出と処理を全部Perlで書かなければならない
    • 加工自体はUNIXコマンドでいいんだよね……という場合面倒
    • でもUNIXコマンド単体では抽出がうまくできない……
  • shell scriptでやろうとするとプロセスがforkしまくる
    • 重い!!!遅い!!!
  • teipは子プロセスを「行ごとに1単位を入力し,同じ数の行を返さなければならない」という原則で縛ることで使い回すことに成功!!
    • すなわち行ごとに出力が独立していて,同じ数だけ行を返せればよい
      • UNIX哲学に従った,フィルタとして振る舞う数多くのコマンド
        • date -f など

これにより複雑で大きな問題がシンプルな複数の問題に変換されていてすごい。「パイプが賢くなったらどうなる?」というアイデアが現実の問題を分解する美しい次元になったのだ。

teip使いそうな便利機能

  • コマンドを指定しない
    • フィルタにヒットする箇所が[]で括られて色が付く。動作確認に使える
  • -g
    • 正規表現を指定してフィルタする
    • -o: マッチした行ではなく,マッチした箇所をパイプする
  • -z
    • NUL文字が行デリミタになる
  • -v
    • マッチをinvertする(grepと同じ)

良さそう

あーエレガントで良いなと思ったのでこのエントリを書いた。仕事でも使ってみたい。

貴様!この記事の筆者をフォローしてください!(しなさい)