現場のシェルスクリプトにおいて、使われる頻度の多い関数はおおよそ下記のとおりです。
- 英数字チェック
- 数値チェック
- プロセスチェック
- ポートチェック
特に規定はありませんが、「true/false」で判定される関数名には、「is〇〇」や「check〇〇」と言うように命名するのが慣例です。
その他、〇〇を取得する関数には「get〇〇」、〇〇設定する関数には「set〇〇」と言った具合です。一番最初に「動詞」を付けることで、可読性が大きく向上するためです。
チェック関数の作成
英数字チェック「isAlphaNum()」
入力された値が英数字かチェックします。
# --------------------------------------------------
# Check the value contains only alphanumeric or not.
# --------------------------------------------------
# param1 value
# return 0:alnum 1:not alnum
# --------------------------------------------------
isAlphaNum() {
val="$(echo $1 | sed -e 's/[^[:alnum:]]//g')"
if [ "$val" != "$1" ]; then
return 1
fi
return 0
}
正規表現「alnum」を使用して、引数「$1」を英数字へ置換しています。置換後の値と引数の値が一致しない場合「1(false)」を返却、一致すれば「0(true)」を返却します。
数値チェック「isNumeric()」
入力された値が数値かチェックします。
# --------------------------------------------------
# Check the value is some number or not.
# --------------------------------------------------
# param1 value
# return 0:numeric 1:other
# --------------------------------------------------
isNumeric() {
expr "$1" + 1 >/dev/null 2>&1
if [ $? -ge 2 ]; then
return 1
fi
return 0
}
関数内部で引数「$1」へ数値の「1」を加算しています。失敗すれば数値ではないと判断出来る為「1(false)」を返却、成功した場合は「0(true)」を返却しています。
プロセスチェック「isProcAlive()」
プロセス実行の有無を判定します。
# --------------------------------------------------
# Check the keyword is in process table or not.
# --------------------------------------------------
# param1 specify the process keyword you want to check
# return 0:is in process table 1:could not find
# --------------------------------------------------
isProcAlive() {
cnt=`ps auxw | grep $1 | grep -v grep | grep -v $SCRIPT_NAME | wc -l`
if [ $cnt -eq 0 ]; then
return 1
fi
return 0
}
「ps」コマンドで引数「$1」にマッチしたプロセスを抜き出し、その中から「grep -v(除外)」コマンドで「grep」コマンド自体のプロセス及び「$SCRIPT_NAME(実行シェル)」のプロセスを除外しています。最後に抽出した行数をカウントして、0なら「1(false)」を返却、0以外の場合は「0(true)」を返却しています。
ポートチェック「isPortAlive()」
ポートのリスニング有無を判定します。
# --------------------------------------------------
# Check the port is listening or not.
# --------------------------------------------------
# specify the port number you want to check
# return 0:listening 1:closed
# --------------------------------------------------
isPortAlive() {
cnt=`netstat -tan | grep ":$1" | grep -w 'LISTEN' | wc -l`
if [ $cnt -eq 0 ]; then
return 1
fi
return 0
}
「netstat」コマンドで通信中の情報の中から引数「$1」にマッチしたポート番号を抜き出し、その中から「grep -w(単語検索)」で一致する文字列「LISTEN」を抽出しています。最後に抽出した行数をカウントして、0なら「1(false)」を返却、0以外の場合は「0(true)」を返却しています。
共通関数定義ファイルへ実装する
# shell scripts common resource
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#
# common.shrc ver.1.0.0 2020.04.24
#
# Usage:
# --------
#
# Description:
# 各種機能より呼び出される共通機能を実装する。
#
# 設計書
# none
#
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# ------------------------------------------------------------
# Constant declaration(定数の宣言領域)
# ------------------------------------------------------------
BASE_PATH=${BASE_PATH:-"/root/scripts"}
COM_PATH=${BASE_PATH}/com
ETC_PATH=${BASE_PATH}/etc
LOG_PATH=${BASE_PATH}/log
TMP_PATH=${BASE_PATH}/tmp
REP_PATH=${BASE_PATH}/rep
SCRIPT_NAME=`basename $0`
JOB_OK=0
JOB_WR=1
JOB_ER=2
MSG_CONF=${ETC_PATH}/message.conf
# ------------------------------------------------------------
# functions (関数を記述する領域)
# ------------------------------------------------------------
(省略)前回までの関数が記述されている領域
# -------------------------------------------------- 👈 ここから追記
# Check the value contains only alphanumeric or not.
# --------------------------------------------------
# param1 value
# return 0:alnum 1:not alnum
# --------------------------------------------------
isAlphaNum() {
val="$(echo $1 | sed -e 's/[^[:alnum:]]//g')"
if [ "$val" != "$1" ]; then
return 1
fi
return 0
}
# --------------------------------------------------
# Check the port is listening or not.
# --------------------------------------------------
# param1 value
# return 0:listening 1:closed
# --------------------------------------------------
isPortAlive() {
cnt=`netstat -tan | grep ":$1" | grep -w 'LISTEN' | wc -l`
if [ $cnt -eq 0 ]; then
return 1
fi
return 0
}
# --------------------------------------------------
# Check the keyword is in process table or not.
# --------------------------------------------------
# param1 specify the process keyword you want to check
# return 0:is in process table 1:could not find
# --------------------------------------------------
isProcAlive() {
cnt=`ps auxw | grep $1 | grep -v grep | grep -v $SCRIPT_NAME | wc -l`
if [ $cnt -eq 0 ]; then
return 1
fi
return 0
}
# --------------------------------------------------
# Check the port is listening or not.
# --------------------------------------------------
# return 0:listening 1:closed
# --------------------------------------------------
isPortAlive() {
cnt=`netstat -tan | grep ":$1" | grep -w 'LISTEN' | wc -l`
if [ $cnt -eq 0 ]; then
return 1
fi
return 0
}
実行シェルスクリプトの作成
チェック関数確認用に「httpd」サービスを使用します。
#!/bin/sh
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#
# ver.1.0.0 yyyy.mm.dd
#
# Usage:
# # sh /root/scripts/bin/check.sh
#
# Description:
# 例題コマンド実行スクリプト
#
# 設計書
# なし
#
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
. `dirname $0`/../com/comFunc.shrc
# ----------------------------------------------------------
# variables (変数の宣言領域)
# ----------------------------------------------------------
scope="var"
rc=${JOB_ER}
# ----------------------------------------------------------
# functions (関数を記述する領域)
# ----------------------------------------------------------
scope="func"
# --------------------------------------------------
# devider.
# --------------------------------------------------
# return N/A
# --------------------------------------------------
line (){
echo -e "\\n ------------"
echo -e " ▼ ${1}"
}
# ----------------------------------------------------------
# pre-process (事前処理ロジックを記述する領域)
# ----------------------------------------------------------
scope="pre"
startLog
# Set a trap.
trap abort 1 2 3 15
# ----------------------------------------------------------
# main-process (メインロジックを記述する領域)
# ----------------------------------------------------------
scope="main"
# 英数字チェック「isAlphaNum()」👈 英数字チェック
line "isAlphaNum()"
var="ab123"
if isAlphaNum ${var} ; then
logOut "[ ${var} ]は、英数字です。"
else
logOut "[ ${var} ]は、英数字ではありません。"
fi
# 数値チェック「isNumeric()」👈 数値チェック
line "isNumeric"
var="12345"
if isNumeric ${var} ; then
logOut "[ ${var} ]は、数値です。"
else
logOut "[ ${var} ]は、数値ではありません。"
fi
# プロセス起動/停止チェック「isProcAlive()」👈 プロセス起動/停止チェック
line "isProcAlive()"
var="httpd"
if isProcAlive ${var} ; then
logOut "[ ${var} ]は、起動中です。"
else
logOut "[ ${var} ]は、停止中です。"
fi
# ポートチェック「isPortAlive()」👈 ポートチェック
line "isPortAlive()"
var="80"
if isPortAlive ${var} ; then
logOut "[${var}]を、リスニング中です。"
else
logOut "[${var}]を、リスニングしていません。"
fi
if [ $? -eq ${JOB_OK} ]; then
rc=${JOB_OK}
fi
# ----------------------------------------------------------
# post-process (事後処理ロジックを記述する領域)
# ----------------------------------------------------------
scope="post"
exitLog ${rc}
[実行結果]
例として「httpd」プロセスを起動して、シェルスクリプト「check.sh」を実行します。
[root@CentOS7 bin]# sh check.sh
[root@CentOS7 bin]# cd ../log
[root@CentOS7 log]# cat check.log
2020-05-13 16:56:08 [ pre ] SCRIPT:[ check.sh ] PID:[ 11135 ] STARTED LOG.
------------
▼ isAlphaNum()
2020-05-13 16:56:08 [ main ] [ ab123 ]は、英数字です。
------------
▼ isNumeric
2020-05-13 16:56:08 [ main ] [ 12345 ]は、数値です。
------------
▼ isProcAlive()
2020-05-13 16:56:08 [ main ] [ httpd ]は、起動中です。
------------
▼ isPortAlive()
2020-05-13 16:56:08 [ main ] [80]を、リスニング中です。
2020-05-13 16:56:08 [ post ] SCRIPT:[ check.sh ] PID:[ 11135 ] ENDED LOG with NOMAL.
[root@CentOS7 log]#
※ 本スクリプト利用により発生した利用者の損害全てに対し、いかなる責任をも負わないものとし、損害賠償をする一切の義務はないものとします。