set -o errexit #(1)
set -o nounset #(1)
set -o noclobber #(1)
umask 0027 #(2)
export PATH="$(command -p getconf PATH)${PATH:+:$PATH}" #(3)
export POSIXLY_CORRECT='200809' UNIX_STD='2003' \
COMMAND_MODE='unix2003' XPG_SUS_ENV='ON' #(4)
atexit() { set -- $?
...
trap - EXIT
exit $1
}
trap 'atexit' EXIT HUP INT QUIT ABRT ALRM TERM
解説
-
set組み込み命令による一連の設定
- errexit
-
命令が失敗した際,直ちに即譜全体を終了(例外あり)。
- nounset
-
未設定の変数を参照した際に終了。
- noclobber
-
出力転送演算子>による既存譜類の上書きを防止する。
-
譜類作成時の許可設定 これ、PATH設定の前でも良いの?
-
`$PATH`変数設定。
-
機構をPOISXに準拠させる
- POSIXLY_CORRECT
-
GNU系 (参考: 標準準拠 - GNU Coreutils)
- UNIX_STD
-
HP-UX (参考: HP-UX 11i 3版 変更通知452頁)
- COMMAND_MODE
-
macOS (参考: compat(5))
- XPG_SUS_ENV
-
IBM AIX (参考: Korn仕類 - IBM AIX V7.2)
OPTIND=1; while getopts 'o:' OPTNAME; do
case $OPTNAME in
'o') (応付子‘o’に対する処理 $OPTARG);;
esac
done; shift $(($OPTIND - 1))
die() {
# 文言を表示して不成功する
# 使用法: die [-s <exit_status>] [<message>]
# 被演算子:
# <exit_status> 終了状態
# (既定は直前の返り値か,もしもそれが0なら1)
# <message> 表示する文言
_exit_status="$?"
OPTIND=1; while getopts 's:' _opt; do
case $_opt in
's') _exit_status="$OPTARG" ;;
esac
done; shift $(($OPTIND - 1))
if [ $# -ge 1 ]; then
printf '[%s] \033[1m\033[31m誤り\033[39m\033[22m: %s\n' \
"${0##*/}" "$1"
shift
else
printf '[%s] \033[1m\033[31m誤り\033[39m\033[22m\n' \
"${0##*/}"
fi
exit $(($_exit_status?$_exit_status:1))
} >&2
POSIX地域特性の場合はそれに対応した文字列,そうでなければ例え不正な形式であろうと言語符号と見做される部分を抜き出す。
if [ "${LC_MESSAGES=$(locale 2> '/dev/null' | \
sed -n -e 's/^LC_MESSAGES="\([^"]*\)"$/\1/p')}" = 'C' \
-o "$LC_MESSAGES" = 'POSIX' ];then
echo 'und-u-va-posix'
else
echo "${LC_MESSAGES%%_*}"
fi
# '\033[>c'を送ると第2端末特性応答が返ってくる。
# 他の応答も同様。
gettermrsp() {
set -- "$(stty -g)"
stty -echo -icanon min 0 time 1
printf '\033[>c' > /dev/tty &&
< /dev/tty cat
stty "$1"
}
解説
(未稿)
isbigend() {
return \
$(printf '\001' | od -A n -t o2 | cut -c 6)
}
解説
(未稿)
所与のUTF-8バイト列をUnicode符号位置へと復号(TODO: これ,「符号化」かも知れない……)する。 Unicodeの表記法は, 『Unicode標準 13.0版』附属書A「表記の取決め」 の表A-1「拡張BNF」を採用した。
iconv(1)命令自体はPOSIXに規定されているものの,それがUTF-8及びUCS-4BEの入出力に対応しているとは限らない。 従ってこの方法は真の意味でPOSIXに準拠しているとは言えず,可搬ではない。
とは言え,近代的な運用機構であれば,Unicodeへの対応がある程度見込めるので,ある程度有用ではあるだろう。
iconv -f UTF-8 -t UCS-4BE |
od -A n -t x1 -v |
sed -e 's/'\
' \([[:xdigit:]]\{2\}\)'\
' \([[:xdigit:]]\{2\}\)'\
' \([[:xdigit:]]\{2\}\)'\
' \([[:xdigit:]]\{2\}\)'\
'/\\U\1\2\3\4/g;s/U0000/u/g'
『Unicode標準 13.0版』3章「適合性」 3.9「Unicode符号化形式」にある表3-7「整形式UTF-8バイト列」(127頁)を参考にして,解析する。
解説
まず,入力バイト列を1バイトずつ区切り16進数で書き出す。 od(1)命令には行番号を付けたり同一バイトの連続を省略したりする機能があるが, これを無効にする。
(すいません,未稿です)
#!/bin/sh
set -o errexit
set -o nounset
set -o noclobber
umask 0022
export PATH="$(command -p getconf PATH)${PATH:+:$PATH}"
export POSIXLY_CORRECT='200809' UNIX_STD='2003' \
COMMAND_MODE='unix2003' XPG_SUS_ENV='ON'
set -- $(date -u +'%Y 1%j 1%H 1%M' && \
date +'%Y 1%j 1%H 1%M') # (1)
# +5:45 Nepal
#set -- 2020 1366 123 159 2021 1001 105 145
# -3:30 Canada
#set -- 2020 1001 103 128 2019 1365 123 159
set -- "$(( ($6 - ($1 == $5 ? $2 : $6 + ($1 - $5))) * 1440 \
+ ($7 - $3) * 60 + ($8 - $4) ))" # (2)
printf '%+03d:%02d\n' \
"$(( $1 / 60 ))" \
"$(( ${1%%[!-]*}1 * ($1 - ($1 % 5 && 1)) % 60 ))" # (3) (4)
解説
<1>
まず,現在の協定世界時および機構標準時の出力を得る。通年日(%j
)・時(%H
)・分(%M
)は各々0で頭埋めされた出力であるが,後に算術展開で扱う際に先頭の0が8進数標識だと見做されるのを避けるべく1を前置する。結局,両者(協定世界時及び機構標準時)の差分を取る過程で,先頭の1は打ち消し合う。また,この過程において,協定世界時の方が機構標準時より必ず先んじて処理・出力される(&&制御子の役割)為,もしも両者の実行の間に分を跨いだ場合,機構標準時の方が必ず遅れている(後述の処理に使用)。
<2>
次に,協定世界時及び機構標準時の通年日・時・分それぞれの差分を分を単位として取る。この過程で,時・日跨ぎ(注意: 命令実行の間に跨いだ場合に限らない。協定世界時との時差が+09:00で,協定世界時が23:50だった場合を考えよ)に関しては,それぞれ時($3`と
$7`)・通年日($2`と
$6`)の差分を加えることによって適切に対処できる。通年日の差分を取る際,年跨ぎを考慮(年($1`と
$5`)の値の相等で判定)して,年の差(±1)を機構標準時の通年日に足し合わせることで帳消す。
<3> ここで,(両者の実行の間に←?)分を跨いだ場合の処理をする。協定世界時との時差の最小単位は15分であり,協定世界時及び機構標準時の出力の間で分を跨いだ場合には機構標準時の方が必ず遅れていることを踏まえると,(分での)差分の(符号付き)下1桁について,協定世界時との時差が正の場合には「1」または「6」(従って-1で帳消し)であり,負の場合には「-4」なたは「-9」(従って-1で帳消し)となる筈である。故に,分跨ぎは,差分が5の倍数でない場合に差分から1を除くという処理で適切に対処できる。猶,分跨ぎに伴って時・日・年を跨ぐ場合もあるが,分跨ぎに由来しない差分に関しては前述までの処理で適切に打ち消されている。
<4> 最後に,分での差分を時・分に分ける。この時,時に関しては差分の正負を明示して出力し,分に関しては絶対値を取る。
isadm() { [ $(id -u) -eq 0 ] || return 77; }
解説
残念ながらPOSIXでは特権管理者 (所謂 “root” とか “admin” とか) の用者識別子を明確に定義していない( 定義 / 3.436使用者識別子 にその趣旨の記載が見当らない)ものの, 通則0であるようだ(参考: getpwuid / 特権管理者の項目を取得する )。 これに拠って,現在の用者識別子が0であれば特権管理者と見做すことにする。
for _a in "$@"; do
shift
# 一致する条件
# 編集処理
# そうでない条件
set -- "$@" "$_a"
done
(解説未稿)
例 “-d” という引数を削除するが,その他の引数は順番も考慮して保存する。
set -- -a -b c -d -x # これは本来外部で与えられる。
for _a in "$@"; do
shift
case $_a in
-d) ;;
*) set -- "$@" "$_a" ;;
esac
done
(これは即譜の実行等には直接影響しない為,附録とする)
: '@prefix : <http://purl.org/net/ns/doas#>. <> a :Script;
:一行説明 "即譜の説明。";
:作成日 "YYYY-MM-DD";
:公開版 ( [:版 "0.1.1"; :作成日 "YYYY-MM-DD"]
[:版 "0.1.0"; :作成日 "YYYY-MM-DD"] );
:作成者 "cmplstofB";
:権利 "ⓒ YYYY cmplstofB";
:ライセンス <http://www.wtfpl.net/txt/copying/>;
:依存関係 "POSIX.1-2017".'
@prefix : <http://purl.org/net/ns/doas#>. <> a :Script;
:一行説明 "即譜の説明。";
:作成日 "YYYY-MM-DD";
:公開版 ( [:版 "0.1.1"; :作成日 "YYYY-MM-DD"]
[:版 "0.1.0"; :作成日 "YYYY-MM-DD"] );
:作成者 "cmplstofB";
:権利 "ⓒ YYYY cmplstofB";
:ライセンス <http://www.wtfpl.net/txt/copying/>;
:依存関係 "POSIX.1-2017".
(解説未稿)