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 $?
}
使用について
バグは発見するたびに潰していますが利用する場合は自己責任でお願いします
- 2023/6/21 バグ修正
- 2023/7/20 バグ修正