前書き
本記事では、自作したPython3.xスクリプトのlibMergeについて記載します。
libMergeは、Bashライブラリ内の関数定義をShellScriptにマージする機能を持ちます。
正確には、Script内で使用されている関数の定義部分のみをBashライブラリから抽出し、
「抽出した関数+元々のScriptの内容」を記載したScriptを新規作成します。
なお、libMergeの作成理由は、以下の通りです。
1. Bashは汎用的なライブラリが存在せず、ライブラリ内の関数の機能に関する共通認識がない。
そのため、第三者が関数定義を参照しやすいScriptの提供が好ましい。
2. 第三者のために、ライブラリの関数定義をScriptに手動で転記する事は避けたい。
3. 単一のファイルで完結していないScriptは、可搬性が低い。
ライブラリがインクルードできない場合、ライブラリが改変された場合などは動作しなくなる。
ちなみに、2005年に「シェルスクリプトを共有してマージするshsubrmerge(CodeZine)」という記事で、
ほぼ同じ機能のScriptが公開されています。まさに、車輪の再発明です。
さらに言及すれば、同等の機能を持つ有名なパッケージが存在しないようなので、
需要がない事が予想されます。自分の問題を解決できるから良いんだ(・言・)
目次
1. libMergeのインストール
2. 参考ライブラリ:bashLib
3. libMergeのオプション
4. libMergeの使用手順
5. libMergeの処理(仕組み)
6. Limitation
libMergeのインストール
Githubに公開してあるため、以下の手順(Debian想定)で取得できます。
libMergeのインストールディレクトリは、"/usr/local/bin/"以下となります。
$ git clone https://github.com/nao1215/BashScriptsCompilation.git -b master
$ cd BashScriptsCompilation
$ sudo ./installScripts # インストールスクリプト
サンプルライブラリ:bashLibについて
Bashライブラリをお持ちの方は少ないと思われるので、サンプルライブラリbashLibを用意しました。
先ほどのインストール手順によって、bashLibもインストールされます。
なお、bashLibに存在する関数は、以下の通りです。
関数名 | 説明 |
---|---|
errMsg | 標準出力にエラーメッセージを赤文字で表示 |
warnMsg | 標準出力にエラーメッセージを黃文字で表示 |
checkArgc | 引数の個数をチェック |
isFile | ファイルが存在するかどうかをチェック |
isDir | ディレクトリが存在するかどうかをチェック |
isSubshell | scriptが"source"コマンドで実行されているかを確認 |
isNumeric | 変数が数値化どうかをチェック |
isNull | 変数(文字列)がNullかどうかをチェック |
isRoot | ユーザがrootかどうかをチェック |
++ | 変数(数値)をインクリメント |
-- | 変数(数値)をデクリメント |
AplusB | 変数に指定の値を加算 |
AminusB | 変数に指定の値を減算 |
_sum | 変数(数値)を加算 |
makeDir | 各種確認の後、ディレクトリを作成 |
makeEmptyFile | 各種確認の後、0Byteのファイルを作成 |
getLineNum | ファイルの行数を取得 |
dos2unix | ファイルをwindows形式からunix形式に変換 |
libMergeのオプション
オプション | 説明 |
---|---|
-l(--lib) | BashライブラリへのPATHを記載。 |
-s(--script) | ライブラリ内の関数定義を付与したいScriptへの PATHを記載。 |
-o(--output) | 関数定義を転記したスクリプト(新規作成)の名前を 変更したい場合、ファイル名を記載。 (デフォルト:"m_<original_scriptname>)" |
libMergeの使用手順
例として、以下のようなサンプルスクリプト(sample.sh)を用意します。
sample.shでは、"/usr/local/bin/bashLib"内で定義されたmakeDir()、errMsg()を使用しています。
これらの関数を使用するため、"source"コマンドによってライブラリをインクルードする必要があります。
#!/bin/bash
# Description : Sample Script
source /usr/local/bin/bashLib # ライブラリのインクルード
makeDir "dir" # ライブラリ関数
errMsg "Sample" # 同上
$ ./sample.sh
make directory dir
Sample
libMergeを用いて、前述のsample.shに、関数定義を付与します。
なお、sample.shに直接関数の定義を挿入するのではなく、m_sample.shという新規Scriptが生成されます。
ここでの新規Scriptの名前は、"-o"オプションで変更する事ができます。
$ ls
sample.sh
$ libMerge -s sample.sh -l /usr/local/bin/bashLib
$ ls
m_sample.sh sample.sh
生成されたm_sample.shは、以下の通りです。
関数定義はScriptのヘッダ以下に挿入され、Script(sample.sh)で用いられている関数定義しか転記されません。
#!/bin/bash
# Description : Sample Script
function errMsg() {
local message="$1"
echo -n -e "\033[31m\c" # Escape sequence to make text color red
echo "${message}"
echo -n -e "\033[m\c" # Escape sequence to restore font color
}
function makeDir() {
local dir_path="$1"
checkArgc "$#"
if [ -d "${dir_path}" ]; then
echo "Directory "${dir_path}" already exists. Not make it."
else
mkdir -p $1
if [ "$?" = 0 ]; then
echo "make directory "${dir_path}""
fi
fi
}
source /usr/local/bin/bashLib # ライブラリのインクルード
makeDir "dir"
errMsg "Sample"
libMergeの処理(仕組み)
以下に、libMergeの処理の概要を示します。
1. オプションチェック(不備があればエラー通知)
2. Bashライブラリをパースし、関数定義の開始行番号と終了行番号のリストを作成
3. Bashライブラリに存在する関数の名前を取得
4. 手順2の結果を元に、関数単位で関数の定義部分を取得。関数名をキー値として、定義を辞書で管理
5. Scriptをパースし、Script内で使用している関数以外をリスト、辞書から削除
6. Scriptのコピー(m_<script_name>)の作成中、辞書の要素(関数定義)をScriptのヘッダ以下に挿入
Limitation
・関数定義部分の抽出(特に定義終了部)は、改良の余地があります。
・元のScriptに存在するライブラリインクルード処理を削除する機能は、未実装です。
・十二分なテストを実施していません。
最後に
「2017年の目標に"パッケージ作成(C言語)"があるから、libMergeをC言語で実装しよう」
そのような事を設計時(20117/2/17の睡眠時)に考えましたが、Pythonで実装して正解でした。
また、Bashのライブラリ化を難しくしている原因は、
「戻り値の欠如」「リダイレクト・パイプを駆使するBashの性質」ではないかと、
今回のlibMergeおよびbashLibの作成で身を持って体感しました。
ライブラリ化の利点は、「ワンライナー(シェル芸)の可読性向上」「テンプレ処理の集約」ぐらいで、
それ以上を求めた優れたライブラリの作成を試みる場合、泥沼に陥りそうです。