シェルスクリプトでたまに必要になる、ちょっとした処理を関数にしました。
たった数行の処理をわざわざ関数にする目的の一つは、スクリプトの可読性を向上するためです。例えばdate +'%F %T'
とnow
では後者の方が意図を理解しやすくなります。
もう一つの目的は、たまにしか使わないコマンドのオプションや文法などのナレッジを関数のコードにまとめておくことで、自分が忘れた時に見直しやすくするためです。
数値
整数(10進数)の判定
引数を 10進数の整数と判定できたら真(終了ステータス 0)を返す関数です。
# $1 整数かを判定する文字列
function is_integer() {
[[ ${1} == "" ]] && return 1
printf "%d" ${1} >/dev/null 2>&1
}
printf は"%d"
で整数に変換できない文字が与えられたら偽を返すのですが、空文字列の場合に真を返してしまいます。しかしこの関数では引数が空文字列の場合に偽を返したいので、先に空文字列の判定をしています。
テスト
for value in '-100' '0' '9999999999' '1.1' '-0.2' '3e5' 'A' 'zz' ''
do
if is_integer "${value}"; then
echo "'${value}': OK."
else
echo "'${value}' is NOT integer."
fi
done
結果は以下のようになりました。
- 正/負の整数と 0 で真を返す
- 正/負の小数で偽を返す
-
e
を使った指数表現で偽を返す - 16進数として評価可能な英文字で偽を返す
- 文字列/空文字列で偽を返す
'-100': OK.
'0': OK.
'9999999999': OK.
'1.1' is NOT integer.
'-0.2' is NOT integer.
'3e5' is NOT integer.
'A' is NOT integer.
'zz' is NOT integer.
'' is NOT integer.
補足
空文字列の判定を以下のように書けば bash 以外のシェルでも使えるようになりますが、一般的なプログラム言語と同様の比較演算子==
による可読性を優先しました。
[ -z ${1} ] && return 1
実数の判定
引数を実数と判定できたら真を返す関数です。上の"%d"
を"%f"
に変えただけです。
# $1 実数かを判定する文字列
function is_numeric() {
[[ ${1} == "" ]] && return 1
printf "%f" ${1} >/dev/null 2>&1
}
テスト
for value in '-100' '0' '9999999999' '1.1' '-0.2' '3e5' 'A' 'zz' ''
do
if is_numeric "${value}"; then
echo "'${value}': OK."
else
echo "'${value}' is NOT numeric."
fi
done
結果は以下のようになりました。
- 正/負の整数と 0 で真を返す
- 正/負の小数で真を返す
-
e
を使った指数表現で真を返す - 16進数として評価可能な英文字で偽を返す
- 文字列/空文字列で偽を返す
'-100': OK.
'0': OK.
'9999999999': OK.
'1.1': OK.
'-0.2': OK.
'3e5': OK.
'A' is NOT numeric.
'zz' is NOT numeric.
'' is NOT numeric.
日時
どれも一般的なプログラム言語の経験者が関数の名前を見ただけで、機能と引数を何となく連想できるようにしたつもりです。
現在日時
# $1 書式指定文字列(省略可)
function now() {
date +"${1:-%F %T}"
}
今日の日付
# $1 書式指定文字列(省略可)
function today() {
date +"${1:-%F}"
}
日時の書式設定
# $1 日時を表す文字列
# $2 書式指定文字列(省略可)
function format_datetime() {
date -d "${1}" +"${2:-%F %T}"
}
日時の加算/減算
# $1 日時を表す文字列
# $2 正/負の整数(未来/過去)
# $3 $2の単位 {year|month|day|hour|minute|second}
# $4 書式指定文字列(省略可)
function add_datetime() {
if (( ${2} < 0 )); then
local date_opt="$((${2} * -1)) ${3}s ago"
else
local date_opt="${2} ${3}s"
fi
date -d "${1} ${date_opt}" +"${4:-%F %T}"
}
テスト
add_datetime '1999-12-31 23:59:59' 1 second
add_datetime '1999-12-31 23:59:59' -1 second
add_datetime '1999-12-31 23:59:59' 180 day '%Y/%m/%d %H:%M:%S'
add_datetime '1999-12-31 23:59:59' -180 day '%Y/%m/%d %H:%M:%S'
add_datetime '1999-12-31 23:59:59' 10 hour '%Y/%m/%d %H:%M:%S'
add_datetime '1999-12-31 23:59:59' -10 hour '%Y/%m/%d %H:%M:%S'
add_datetime '1999-12-31 23:59:59' 20 year '%Y年%m月%d日 %H時%M分%S秒'
add_datetime '1999-12-31 23:59:59' -20 year '%Y年%m月%d日 %H時%M分%S秒'
以下のように意図した結果になりました。
2000-01-01 00:00:00
1999-12-31 23:59:58
2000/06/28 23:59:59
1999/07/04 23:59:59
2000/01/01 09:59:59
1999/12/31 13:59:59
2019年12月31日 23時59分59秒
1979年12月31日 23時59分59秒