rm /blog

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【UNIX】shファイル内で使う共通処理の関数化コーディングについて

何度も同じような処理を実行するような場合は、
それらの処理を共通関数化してまとめておいたほうがいい。
「関数化」の記述は以下の赤太字部分の通り。

#!/bin/sh

test_function "TEST1"    ←①

test_function() {
        echo "Argument is $1"
}

test_function "TEST2"    ←②

exit 0

 


 

 


関数内では、「$1」で第一引数、「$2」で第二引数、…「$[n]」で第n引数を取得できる。
これはshファイル実行時における引数の取り方と同じ。
別のshファイルが自分の中にもう一ついるようなイメージ。

なお、関数としてまとめた処理を呼び出す場合は、呼び出す処理より手前に関数化の定義が必要である。
↑をshファイルにしてそのまま実行すると少なくとも「①」の部分でエラーになる。

test.sh[3]: test_function: not found [ファイルもディレクトリもありません。] ←①
Argument is TEST2 ←②


こんな感じ。
①の時点では「test_function」の存在が認知されていない(①よりも下にtest_functionの定義がある)ので、①では怒られる。
②は問題なく動く。



↑の例は無茶苦茶単純な例で、与えられた引数をechoで標準出力するだけのもの。
関数化してまとめるメリットをあまり感じない例である。
よく使うのはfindとか、その辺との連動であろう。
下記の例では、引数にディレクトリと最終更新からの経過日数をもらい、
それに該当するファイルを削除する関数である。

#!/bin/sh


deleteFile() {
        # 第一引数:対象ディレクトリ
        # 第二引数:最終更新からの経過日数
        # 対象ディレクトリ配下から指定日数経過しているファイルを削除する処理。
        find $1 -type f -mtime +${2} -exec rm -rf {} \;
}

# /home/work配下の30日より前のファイルを削除
deleteFile /home/work/ 30

# /home/test配下の10日より前のファイルを削除
deleteFile /home/test/ 10
…


みたいなかんじ。いちいちfindコマンドを2行書かなくても済んだということ。
まあ2行くらいならわざわざ関数化なんてしなさそうだが、
これが10や20あるとさすがにその行数find書くのが馬鹿らしくなってくるし、
コードも煩雑になって可読性・保守性も下がるので、
こんな風にまとめあげてしまったほうが良い。



ちなみに関数部分のコードはなんとなくインデントを一段階変えたくなるが、
関数内でインデント下げつつsqlplusとかの「ここからここまでまとめてヨロシク(ヒアドキュメント)」をやろうとすると怒られる。

sqlplusTest() {
#本来ここから記述をスタートさせるが…
	#関数内なので一段落インデントを下げてここから記述をスタートさせている
	sqlplus -s TESTUSER/TESTPASS@TESTDB << YOROSIKU
	select sysdate from dual;
	exit;
	YOROSIKU

}

sqlplusTest


こんな感じ↑の書き方である。
「<<」を使った書き方がインデントの変更に対応してないみたいで、


test.sh: line 5: syntax error at line 10: `<<' unmatched


と、言われてしまう。
個人的に書き方が気持ち悪いんだが、こういう場合は仕方ないのでインデントを詰めて

sqlplusTest() {
#本来ここから記述をスタートさせるのでここに合わせる
sqlplus -s TESTUSER/TESTPASS@TESTDB << YOROSIKU
select sysdate from dual;
exit;
YOROSIKU

}
sqlplusTest


と書けば正しく動作する。