LoginSignup
0
0

bashで使う自作共通関数

Last updated at Posted at 2023-05-26

bashで使う自作共通関数のサンプル

開発環境

cat /etc/os-release
master@sv-server:~/mkusb$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

シェルの初期設定

シェルの初期設定
#!/bin/bash

### initialization ############################################################
#	set -n								# Check for syntax errors
#	set -x								# Show command and argument expansion
	set -o ignoreeof					# Do not exit with Ctrl+D
	set +m								# Disable job control
	set -e								# Ends with status other than 0
	set -u								# End with undefined variable reference

	trap 'exit 1' 1 2 3 15

共通関数

is numeric

機能: 入力値が数値か確認

出力値 意味
0 数値
1 数値以外を含む
funcIsNumeric
function funcIsNumeric () {
	if [[ "${1:-""}" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
		echo 0
	else
		echo 1
	fi
}

string output

機能: 文字の指定数出力

入力値 意味
$1 出力文字数
$2 出力文字
出力値 意味
文字列 指定した文字数の文字列

ASC文字のみ対象

funcString
function funcString () {
	declare -r OLD_IFS="${IFS}"
	IFS=$'\n'
	if [[ "$1" -le 0 ]]; then
		echo ""
	else
		if [[ "$2" = " " ]]; then
			echo "" | awk '{s=sprintf("%'"$1"'.'"$1"'s"," "); print s;}'
		else
			echo "" | awk '{s=sprintf("%'"$1"'.'"$1"'s"," "); gsub(" ","'"$2"'",s); print s;}'
		fi
	fi
	IFS="${OLD_IFS}"
}

print with screen control

機能: 文字列の指定数画面出力

入力値 意味
$@ 出力文字列等
出力値 意味
画面 指定した文字数でカットした文字列

SJIS(CP932)変換できない文字を含む場合は正常に機能しません

iconvでUTF-8→CP932→UTF-8と変換
SJISだと "~"(チルダ) を含むと想定外の変換・復元で余分なスペースが出力される
<参照>
https://www.tohoho-web.com/ex/dash-tilde.html

出力文字数の制御は以下の変数で行っています

出力文字数 規定値
COL_SIZE 80
コンソール画面の行列数の取得例
if [[ "$(command -v tput 2> /dev/null)" != "" ]]; then
	ROW_SIZE=$(tput lines)
	COL_SIZE=$(tput cols)
fi
if [[ ${COL_SIZE} -lt 80 ]]; then
	COL_SIZE=80
fi
funcPrintf
function funcPrintf () {
	# https://www.tohoho-web.com/ex/dash-tilde.html
	declare -r OLD_IFS="${IFS}"
	declare -i RET_CD
	declare -r CHR_ESC="$(echo -n -e "\033")"
	declare -i MAX_COLS=${COL_SIZE:-80}
	declare    RET_STR=""
	declare    INP_STR=""
	declare    SJIS_STR=""
	declare -i SJIS_CNT=0
	declare    WORK_STR=""
	declare -i WORK_CNT=0
	declare    TEMP_STR=""
	declare -i TEMP_CNT=0
	declare -i CTRL_CNT=0
	# -------------------------------------------------------------------------
	IFS=$'\n'
	INP_STR="$(printf "$@")"
	# --- convert sjis code ---------------------------------------------------
	SJIS_STR="$(echo -n "${INP_STR}" | iconv -f UTF-8 -t CP932)"
	SJIS_CNT="$(echo -n "${SJIS_STR}" | wc -c)"
	# --- remove escape code --------------------------------------------------
	TEMP_STR="$(echo -n "${SJIS_STR}" | sed -e "s/${CHR_ESC}\[[0-9]*m//g")"
	TEMP_CNT="$(echo -n "${TEMP_STR}" | wc -c)"
	# --- count escape code ---------------------------------------------------
	CTRL_CNT=$((SJIS_CNT-TEMP_CNT))
	# --- string cut ----------------------------------------------------------
	WORK_STR="$(echo -n "${SJIS_STR}" | cut -b $((MAX_COLS+CTRL_CNT))-)"
	WORK_CNT="$(echo -n "${WORK_STR}" | wc -c)"
	# --- remove escape code --------------------------------------------------
	TEMP_STR="$(echo -n "${WORK_STR}" | sed -e "s/${CHR_ESC}\[[0-9]*m//g")"
	TEMP_CNT="$(echo -n "${TEMP_STR}" | wc -c)"
	# --- calc ----------------------------------------------------------------
	MAX_COLS+=$((CTRL_CNT-(WORK_CNT-TEMP_CNT)))
	# --- convert utf-8 code --------------------------------------------------
	set +e
	RET_STR="$(echo -n "${INP_STR}" | iconv -f UTF-8 -t CP932 | cut -b -${MAX_COLS} | iconv -f CP932 -t UTF-8 2> /dev/null)"
	RET_CD=$?
	set -e
	if [[ ${RET_CD} -ne 0 ]]; then
		set +e
		RET_STR="$(echo -n "${INP_STR}" | iconv -f UTF-8 -t CP932 | cut -b -$((MAX_COLS-1)) | iconv -f CP932 -t UTF-8 2> /dev/null) "
		set -e
	fi
#	RET_STR+="$(echo -n -e ${TXT_RESET})"
	# -------------------------------------------------------------------------
	echo -e "${RET_STR}${TXT_RESET}"
	IFS="${OLD_IFS}"
}

download

機能: 保存先のファイルが同じの場合にスキップしてダウンロード

入力値 意味
$@ curlのオプション値
戻り値 意味
$? curlの戻り値
出力値 意味
same 保存先と同じファイルのためダウンロードをしない
get 保存先と異なるファイルのためダウンロードを実行

ダウンロード時に表示されるファイルサイズは厳密では無いので参考までに。
<表示例>
get file: ./mkusb/iso/net/debian-testing-amd64-netinst.iso (642.0 MiB)

funcCurl
function funcCurl () {
#	declare -r OLD_IFS="${IFS}"
	declare -i RET_CD
	declare -i I
	declare INP_URL="$(echo "$@" | sed -n -e 's%^.* \(\(http\|https\)://.*\)$%\1%p')"
	declare OUT_DIR="$(echo "$@" | sed -n -e 's%^.* --output-dir *\(.*\) .*$%\1%p' | sed -e 's%/$%%')"
	declare OUT_FILE="$(echo "$@" | sed -n -e 's%^.* --output *\(.*\) .*$%\1%p' | sed -e 's%/$%%')"
	declare -a ARY_HED=("")
	declare ERR_MSG=""
	declare WEB_SIZ=""
	declare WEB_TIM=""
	declare WEB_FIL=""
	declare LOC_INF=""
	declare LOC_SIZ=""
	declare LOC_TIM=""
	declare TXT_SIZ=""
	declare -i INT_SIZ
	declare -a TXT_UNT=("Byte" "KiB" "MiB" "GiB" "TiB")
	set +e
	ARY_HED=("$(curl --location --no-progress-bar --head --remote-time --show-error --silent --fail --retry-max-time 3 --retry 3 "${INP_URL}" 2> /dev/null)")
	RET_CD=$?
	set -e
	if [[ ${RET_CD} -eq 6 ]] || [[ ${RET_CD} -eq 18 ]] || [[ ${RET_CD} -eq 22 ]] || [[ ${RET_CD} -eq 28 ]] || [[ "${#ARY_HED[@]}" -le 0 ]]; then
		ERR_MSG=$(echo "${ARY_HED[@]}" | sed -n -e '/^HTTP/p' | sed -z 's/\n\|\r\|\l//g')
		funcPrintf "${ERR_MSG} [${RET_CD}]: ${INP_URL}"
#		return
		return ${RET_CD}
	fi
	WEB_SIZ=$(echo "${ARY_HED[@],,}" | sed -n -e '/http\/.* 200/,/^$/ s/\'$'\r//gp' | sed -n -e '/content-length:/ s/.*: //p')
	WEB_TIM=$(TZ=UTC date -d "$(echo "${ARY_HED[@],,}" | sed -n -e '/http\/.* 200/,/^$/ s/\'$'\r//gp' | sed -n -e '/last-modified:/ s/.*: //p')" "+%Y%m%d%H%M%S")
	WEB_FIL="${OUT_DIR:-.}/${INP_URL##*/}"
	if [[ -n "${OUT_DIR}" ]] && [[ ! -d "${OUT_DIR}/." ]]; then
		mkdir -p "${OUT_DIR}"
	fi
	if [[ -n "${OUT_FILE}" ]] && [[ -f "${OUT_FILE}" ]]; then
		WEB_FIL="${OUT_FILE}"
	fi
	if [[ -n "${WEB_FIL}" ]] && [[ -f "${WEB_FIL}" ]]; then
		LOC_INF=$(TZ=UTC ls -lL --time-style="+%Y%m%d%H%M%S" "${WEB_FIL}")
		LOC_TIM=$(echo "${LOC_INF}" | awk '{print $6;}')
		LOC_SIZ=$(echo "${LOC_INF}" | awk '{print $5;}')
		if [[ ${WEB_TIM:-0} -eq ${LOC_TIM:-0} ]] && [[ ${WEB_SIZ:-0} -eq ${LOC_SIZ:-0} ]]; then
			funcPrintf "same    file: ${WEB_FIL}"
			return
		fi
#		if [[ ${WEB_TIM:-0} -ne ${LOC_TIM:-0} ]]; then
#			funcPrintf "diff file: ${WEB_FIL}"
#			funcPrintf "WEB_TIM: ${WEB_TIM:-0}"
#			funcPrintf "LOC_TIM: ${LOC_TIM:-0}"
#		fi
#		if [[ ${WEB_SIZ:-0} -ne ${LOC_SIZ:-0} ]]; then
#			funcPrintf "diff file: ${WEB_FIL}"
#			funcPrintf "WEB_SIZ: ${WEB_SIZ:-0}"
#			funcPrintf "LOC_SIZ: ${LOC_SIZ:-0}"
#		fi
	fi

	if [[ ${WEB_SIZ} -lt 1024 ]]; then
		TXT_SIZ="$(printf "%'d Byte" "${WEB_SIZ}")"
	else
		for ((I=3; I>0; I--))
		do
			if [[ ${WEB_SIZ} -ge $((1024**I)) ]]; then
				INT_SIZ="$(((WEB_SIZ*1000)/(1024**I)))"
				TXT_SIZ="$(printf "%'.1f ${TXT_UNT[${I}]}" "${INT_SIZ::${#INT_SIZ}-3}.${INT_SIZ:${#INT_SIZ}-3}")"
				break
			fi
		done
	fi

	funcPrintf "get     file: ${WEB_FIL} (${TXT_SIZ})"
	curl "$@"
	return $?
}

出力例
image.png

使用について

以下のシェルスクリプトで使用しています

https://github.com/office-itou/Linux/blob/master/installer-usbstick/mkinstallusbstick.sh

バグは発見するたびに潰していますが利用する場合は自己責任でお願いします

  • 2023/6/21 バグ修正
  • 2023/7/20 バグ修正
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0