シェルスクリプトマガジン

逆に、Tukubaiコマンドをシェルスクリプトで実装してみる 後編 (vol.48掲載)

著者:今泉光之 (Twitter: @bsdhack)

Open usp Tukubai は Python により実装されているので Python が動作する環境であればインストール可能です。
公式の配布サイトからソースを取得して展開し make install するだけで Open usp Tukubai は利用可能となります。
ここでは Open usp Tukubai のコマンドを解説します。
ただし以下のように Open usp Tukubai だけでも 55 コマンドも提供されており、その全てを解説するのは無理なので、
特に有用で興味深いコマンドを厳選して紹介します。

前回紹介したcalclock、comma、getlast、ketaに続き、今回はmojihame、self、sm2の3つのコマンドを紹介し、シェルスクリプトでの再現を試みます。
但し今回は紙面と時間の都合で一部の機能やオプションなど実装できていない部分も多いです。
また、動作の把握とメイン処理の実装のみに絞ったので、エラー処理などはまったく実施していません。
そのために実際の業務などには殆ど利用できない実験的なスクリプトとなっています。

mojihame

mojihameとは

テンプレート中に埋め込まれたキーワードをデータに置換して出力します。
キーワードは %数字 の形式で指定し、データ中に出現した順番にテンプレート中の %1、%2 …と置換されます。
データ中の @ はヌル文字として扱われ空文字列に置換されますが -d オプションで @ を別の文字に変更できます。
データ中の _ はスペースに変換して出力されます。_ を出力したい場合は \_ の様に指定します。

-l オプションは行単位での置換処理が実施されます。
入力データは行単位に読み込まれ、入力データの次の行が読み込まれるとテンプレートは先頭から再利用されます。

-l オプションではラベルを指定することができます。
ラベルが指定された場合、テンプレート中でラベルの間に書かれたキーワードのみが置換の対象となります。なおラベルはテンプレート中で2回 (開始と終了) しか書くことができません。
(-h による階層構造に関しては説明が複雑なのでここでは省略します)

mojihameを作ってみよう

基本的な機能は全て awk(1) の組み込み関数で実装しました。
通常モードでは、 awk(1) の BEGIN 処理でデータを全て読み込み配列 data に格納した後で _ の置換処理を行っています。
メイン処理ではテンプレートファイルを読み込み、 match 関数を利用して %数字 のラベルを探して gsub 関数で置換しています。

行モードでは、 BEGIN 処理でテンプレートを全て読み込みハッシュ template に格納しています。
メイン処理では、データを読み込み index 関数を利用して %数字 のラベルが存在する間テンプレートを置換します。
テンプレートに数字のラベルが見付からない場合は、テンプレートの次の行をハッシュ template から取得して処理を続けます。

今回紹介した Tukubai コマンドの中では、これが一番多機能なコマンドでした。非常に複雑で多機能なので、通常モードと行モードの基本的なテンプレート置換機能しか実装しておらず、-l オプションのラベル指定、-h オプションによる階層構造テンプレートなどは実装していません。

self

selfとは

入力データ(ファイルや標準出力)の指定されたフィールドのみを出力します。

フィールドの指定時のオプションで、開始文字と文字列長が指定できます。
例えば 4.3 とした場合は第 4 フィールドの 3 文字目から出力され、5.5.4 とした場合は第 5 フィールドの 5 文字目から 2 文字が出力されます。
マルチバイトの文字の場合、開始文字と文字列長はそれぞれ 1 文字を 2 として計算する必要があり、
マルチバイト文字を文字の中間で分割する様な指定された場合はエラーとなります。

フィールド指定の 0 は全フィールドを表します。
フィールド指定で n/m (n と m はそれぞれ整数) とすることで n 番目から m 番目のフィールドを出力できます。
フィールド指定の NF は現在行のフィールド数に置き換えられ NF-3 (最後から3番目のフィールド) や 2/NF などの利用が可能です。

-d オプションは引数で指定した文字列を区切ることができます。

selfを作ってみよう

self コマンド自体が awk(1) と似ているので、多少冗長になってしまいましたが awk(1) の機能だけで殆ど実装できました。フィールド指定、NF による相対的なフィールド指定、NF からの相対位置による指定、n/m 指定などが動作しています。
ただし OS X 標準の awk(1) はマルチバイト文字には対応していないのでマルチバイト文字を扱うことができません。
Linux で標準的に利用されている GNU awk の場合はマルチバイト文字に対応していますので、今回作成した self コマンドも正しく動作しています。

(次ページに続く)