{clwkb32enc.sh}{awk}{clwkb32.sh実装の記録}{sed}{POSIX仕類によるClockworkのBase32実装}=}(5)

{clwkb32enc.sh実装の記録 K#9-D657/A-CA0D}

AWKでやろうと思ったけど,ビット演算ができない。
→16進数をうまく分割すれば↑なしでもいけそう。
というか非自明な配列が必要なので,AWKでやりたい。
→set命令使ってevalすれば良い。
→???なぜか実行されない(上掲譜<1>)。

AWKで実装(途中)

BEGIN {
hexdig="0123456789abcdef"
c[ 0] = "0"; c[ 1] = "1"; c[ 2] = "2"; c[ 3] = "3";
c[ 4] = "4"; c[ 5] = "5"; c[ 6] = "6"; c[ 7] = "7";
c[ 8] = "8"; c[ 9] = "9"; c[10] = "A"; c[11] = "B";
c[12] = "C"; c[13] = "D"; c[14] = "E"; c[15] = "F";
c[16] = "G"; c[17] = "H"; c[18] = "J"; c[21] = "K";
c[20] = "M"; c[21] = "N"; c[22] = "P"; c[23] = "Q";
c[24] = "R"; c[25] = "S"; c[26] = "T"; c[27] = "V";
c[28] = "W"; c[31] = "X"; c[30] = "Y"; c[31] = "Z";
}
{
delete _f
for (i = 1; i <= NF; i++) {
	_f[2 * i - 1] = index(hexdig, tolower(substr($i, 1, 1))) - 1
	_f[2 * i] = index(hexdig, tolower(substr($i, 2, 1))) - 1
}
print \
c[(_f[1] * 2) + \
  (_f[2] > 7)] \
c[(_f[2] % 8) * 4 + \
  (_f[3] > 7) * 2 + \
  (_f[3] > 5)] \
c[(_f[3] % 4) * 8 + \
  int(_f[4] / 2)] \
c[(_f[4] % 2) * 16 + \
  _f[5]] \
c[_f[6] * 2 + \
  int(_f[7] / 8)] \
c[(_f[7] % 8) * 4 + \
  int(_f[8] / 4)] \
c[(_f[8] % 4) * 8 + \
  int(_f[9] / 2)]
c[(_f[9] % 2) * 16 + \
  _f[10]]
}

これはうまくいきそう。
→ほぼうまくいった。あとは終端処理。

printf '%s' 'foobar' |
od -A n -t x1 |
fold -w 15 |
awk -Wposix -f ./cwb32.awk
  • 遅すぎるのでsed(とその他のPOSIX用類)による実装にする。

→終端処理はsedの置換成功判定と分岐を利用する。

  • 機構が1 byte = 8 bitのバイト降順であることを仮定している。

バイト昇順には対応できそうだが,1 byte != 8 bitはどうしようもなさそう。

ビット→バイト変換算法について

1 byte = 8 bit,バイト昇順を仮定。
バイト順はたぶん判定できるけど,1 byte = $n$ bitはどうする?
printf '\777'とかやって,それがビットでどうあらわされてるかを見る?
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html

→そもそも可搬運用機構界面で1 byte = 8 bitと定められているので(ISO Cでは違うかも,と断り書きはあるが),対応を考えなくてもいいかな。

  • バイト順って-t x1みたいなときに考慮する必要ある

→ない気がする。

  • od(1)の出力で,バイト位置を出力しなかった場合 (-A n),各行の先頭に[:blank:]文字が付けられるのか否かが不明なので,現在のprintf 'xxx'みたいな実装はマズい。

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/od.html
→いかなるときも先頭に\nを入れることで解決。

#!/bin/sh

: '@prefix : <http://purl.org/net/ns/doas#>. <> a :Script;
:一行説明   "ClockworkのBase32実装";
:作成日     "2021-06-03";
:公開版     ( [:版 "0.1.0"; :作成日 "2021-06-03"] );
:作成者     "cmplstofB";
:権利       "ⓒ 2021 cmplstofB";
:ライセンス <http://www.wtfpl.net/txt/copying/>;
:依存関係   "POSIX.1-2017".'

set -o errexit; set -o nounset; set -o noclobber
umask 0027
export PATH="$(command -p getconf PATH)${PATH:+:$PATH}"
export POSIXLY_CORRECT='200809' UNIX_STD='2003' \
       COMMAND_MODE='unix2003' XPG_SUS_ENV='ON'

# \1   |    \2|     |  \3  |     \4     |   \5 |     
# 76543|210 76|54321|0 7654|3210 7|65432|10 765|43210
# -----|--- --|-----|- ----|---- -|-----|-- ---|-----
# xxxxx|xxx xx|xxxxx|x xxxx|xxxx x|xxxxx|xx xxx|xxxxx
#
# 7 : 255 | 3 : 15
# 6 : 127 | 2 :  7
# 5 :  63 | 1 :  3
# 4 :  31 | 0 :  1
#
# 16 8 4 2 1
# x  x x x x

set -- \
  '0' '1' '2' '3' '4' '5' '6' '7' \
  '8' '9' 'A' 'B' 'C' 'D' 'E' 'F' \
  'G' 'H' 'J' 'K' 'M' 'N' 'P' 'Q' \
  'R' 'S' 'T' 'V' 'W' 'X' 'Y' 'Z'

{ printf '\001\001\001\001'; cat; } |
{ printf '\n'; od -v -A n -t x1; } |
tr -s '[[:blank:]]' '\n' |
paste -d ' ' - - - - - |
sed -e '1d;s/'\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\)/'\
'echo printf %s'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
' "\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
' "\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
' "\\${$(((0x\3 \& 15) *  2 + (0x\4 >> 7) + 1))}"'\
' "\\${$((((0x\4 \& 127) >>  2) + 1))}"'\
' "\\${$(((0x\4 \&  3) *  8 + (0x\5 >> 5) + 1))}"'\
' "\\${$(((0x\5 \& 31) + 1))}"/'\
  -e 't;s/'\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\)/'\
'echo printf %s'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
' "\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
' "\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
' "\\${$(((0x\3 \& 15) *  2 + (0x\4 >> 7) + 1))}"'\
' "\\${$((((0x\4 \& 127) >>  2) + 1))}"'\
' "\\${$(((0x\4 \&  3) *  8 + 1))}"/'\
  -e 't;s/'\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\)/'\
'echo printf %s'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
' "\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
' "\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
' "\\${$(((0x\3 \& 15) *  2 + 1))}"/'\
  -e 't;s/'\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\)/'\
'echo printf %s'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
' "\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
' "\\${$(((0x\2 \&  1) * 16 + 1))}"/'\
  -e 't;s/'\
'\([[:xdigit:]]\{2\}\)/'\
'echo printf %s'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + 1))}"/' |
sh |
eval "$(cat)"
printf '\n'

これ,

sed -e '1d
2i\
set -- \\\
  0 1 2 3 4 5 6 7 \\\
  8 9 A B C D E F \\\
  G H J K M N P Q \\\
  R S T V W X Y Z
i\
eval "$(echo printf '"'"'%s'"'"' \\
s/'\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\)/'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
' "\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
' "\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
' "\\${$(((0x\3 \& 15) *  2 + (0x\4 >> 7) + 1))}"'\
' "\\${$((((0x\4 \& 127) >>  2) + 1))}"'\
' "\\${$(((0x\4 \&  3) *  8 + (0x\5 >> 5) + 1))}"'\
' "\\${$(((0x\5 \& 31) + 1))}")"/'\
  -e 't;s/'\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\)/'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
' "\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
' "\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
' "\\${$(((0x\3 \& 15) *  2 + (0x\4 >> 7) + 1))}"'\
' "\\${$((((0x\4 \& 127) >>  2) + 1))}"'\
' "\\${$(((0x\4 \&  3) *  8 + 1))}")"/'\
  -e 't;s/'\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\)/'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
' "\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
' "\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
' "\\${$(((0x\3 \& 15) *  2 + 1))}")"/'\
  -e 't;s/'\
'\([[:xdigit:]]\{2\}\) '\
'\([[:xdigit:]]\{2\}\)/'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
' "\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
' "\\${$(((0x\2 \&  1) * 16 + 1))}")"/'\
  -e 't;s/'\
'\([[:xdigit:]]\{2\}\)/'\
' "\\${$(((0x\1 >>  3) + 1))}"'\
' "\\${$(((0x\1 \&  7) *  4 + 1))}")"/' |
sh

のほうが「安全」な気もする。というのはevalの引数制限(多分ARG_MAX)に引っ掛からないから。
ただし,10倍以上遅くなる。
→と思ったけど,ARG_MAXが適用されるのはexec()機構呼び出しを介した実行時だけで,組込み命令に対しては制限ないのかも。
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html#tag_13_23_03_01
https://www.in-ulm.de/~mascheck/various/argmax/


  • 最終行に強制的に改行を(5-1個)付け足すことで

sedに渡す前処理を簡略に。
sedのN命令は次行がないとsed譜全体を終了してしまうが、それを回避しつつs命令で実質的な最終行を判定する。

  • evalの対象が無駄に複雑なのを簡略。

というかなんでeval "$(echo printf '%s' ${$(引数位置の計算)})"みたいにしてたんだ?eval echo ${$(引数位置の計算)}でいいじゃん。

clockwork→clwk https://www.abbreviations.com/abbreviation/clockwork
base32→b32

という交度英語により命令名をclwkb32.shに。

#!/bin/sh

: '@prefix : <http://purl.org/net/ns/doas#>. <> a :Script;
:一行説明   "ClockworkのBase32実装";
:作成日     "2021-06-03";
:公開版     ( [:版 "0.3.0"; :作成日 "2021-06-29"]
              [:版 "0.2.0"; :作成日 "2021-06-29"]
              [:版 "0.1.0"; :作成日 "2021-06-03"] );
:作成者     "cmplstofB";
:権利       "ⓒ 2021 cmplstofB";
:ライセンス <http://www.wtfpl.net/txt/copying/>;
:依存関係   "POSIX.1-2017".'

set -o errexit; set -o nounset; set -o noclobber
umask 0027
# shellcheck disable=SC2155
export PATH="$(command -p getconf PATH)${PATH:+:$PATH}"
export POSIXLY_CORRECT='200809' UNIX_STD='2003' \
       COMMAND_MODE='unix2003' XPG_SUS_ENV='ON'

# \1   |    \2|     |  \3  |     \4     |   \5 |     
# 76543|210 76|54321|0 7654|3210 7|65432|10 765|43210
# -----|--- --|-----|- ----|---- -|-----|-- ---|-----
# xxxxx|xxx xx|xxxxx|x xxxx|xxxx x|xxxxx|xx xxx|xxxxx
#
# 7 : 255 | 3 : 15
# 6 : 127 | 2 :  7
# 5 :  63 | 1 :  3
# 4 :  31 | 0 :  1
#
# 16 8 4 2 1
# x  x x x x

{ echo; od -v -A n -t x1; } |
{ tr -s '[:blank:]' '\n'; echo; echo; echo; echo; } |
sed -e '1d;2i\
set -- \\\
  0 1 2 3 4 5 6 7 8 9 A B C D E F \\\
  G H J K M N P Q R S T V W X Y Z
H;N;H;N;H;N;H;N
i\
eval printf \\
s/'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)/'\
'"\\${$(((0x\1 >>  3) + 1))}"'\
'"\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
'"\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
'"\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
'"\\${$(((0x\3 \& 15) *  2 + (0x\4 >> 7) + 1))}"'\
'"\\${$((((0x\4 \& 127) >>  2) + 1))}"'\
'"\\${$(((0x\4 \&  3) *  8 + (0x\5 >> 5) + 1))}"'\
'"\\${$(((0x\5 \& 31) + 1))}"/;t
s/'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)/'\
'"\\${$(((0x\1 >>  3) + 1))}"'\
'"\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
'"\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
'"\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
'"\\${$(((0x\3 \& 15) *  2 + (0x\4 >> 7) + 1))}"'\
'"\\${$((((0x\4 \& 127) >>  2) + 1))}"'\
'"\\${$(((0x\4 \&  3) *  8 + 1))}"/;t
s/'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)/'\
'"\\${$(((0x\1 >>  3) + 1))}"'\
'"\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
'"\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
'"\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
'"\\${$(((0x\3 \& 15) *  2 + 1))}"/;t
s/'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)/'\
'"\\${$(((0x\1 >>  3) + 1))}"'\
'"\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
'"\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
'"\\${$(((0x\2 \&  1) * 16 + 1))}"/;t
s/'\
'\([[:xdigit:]]\{2\}\)/'\
'"\\${$(((0x\1 >>  3) + 1))}"'\
'"\\${$(((0x\1 \&  7) *  4 + 1))}"/' |
sh
exit $?

速度も一つ前の実装より30倍!ほど早くなったし(AWK版にくらべるともっと速い),ほぼ満足。

  • 最後の`tr -d '\n'

!現行取り込み中

sedの次あたりの処理,echoが組込用類でない場合を想定してxargsと組み合わせて処理する?

=}
{POSIXにおける文譜}{入力形式に制限がないPOSIX用類}{}{POSIX用類}=}(4)

{入力形式に留意すべきPOSIX用類 K#9-D657/A-D961}

入力譜が文譜でなければならない用類

grep用類::

  • 入力譜は文譜でなければならない。

典拠: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html#tag_20_55_07

expand用類::

  • 入力譜は文譜でなければならない。

典拠: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/expand.html#tag_20_41_07

入力譜にその他の制限がある用類

sed用類::

  • 入力譜は文譜でなければならない。
  • 判定空間および保持空間は最低でも8192バイトを保持できなくてはならない。

典拠: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html#tag_20_116_07, https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html#tag_20_116_13

awk用類::
RS変数が改行文字以外に設定されている,またはRS変数が設定されていない場合は,!!!

Whether the variable RS is set to a value other than a <newline> or not, for these files, implementations shall support records terminated with the specified separator up to {LINE_MAX} bytes and may support longer records.

典拠: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html#tag_20_06_07

fold用類::
‐b応付子非指定時は,入力譜は文譜でなくてはならない。
‐b応付子指定時は,入力譜は文譜でなくてはならないが,{LINE_MAX}バイトの制限はない。

典拠: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/fold.html#tag_20_48_07, https://pubs.opengroup.org/onlinepubs/9699919799/utilities/fold.html#tag_20_48_07

xargs用類::

  • 入力譜は文譜でなければならない。
  • 越化済み新行文字の直後に譜類終了 (EOF) 条件を検出した場合の挙動は未定。

典拠: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/xargs.html#tag_20_158_06

{POSIXにおけるバイト}{clwkb32.sh実装の記録}{POSIX仕類によるClockworkのBase32実装}{バイト順}{仕類即譜}=}(5)

{clwkb32enc.sh K#9-D657/A-FD1C}

算法

仕類即譜で2値譜をあつかうにあたっては,!!!
原理的には2値を可視文字として表わして!!!

5ビットごとの変換を1バイト=8ビット単位の切り出しで行うにあたって,$\operatorname{lcm}(5, 8) = 40$ビット = 5バイトごとに処理するのがよい。

実装

#!/bin/sh

: '@prefix : <http://purl.org/net/ns/doas#>. <> a :Script;
:一行説明   "ClockworkのBase32実装";
:作成日     "2021-06-03";
:公開版     ( [:版 "0.3.0"; :作成日 "2021-06-29"]
              [:版 "0.2.0"; :作成日 "2021-06-29"]
              [:版 "0.1.0"; :作成日 "2021-06-03"] );
:作成者     "cmplstofB";
:権利       "ⓒ 2021 cmplstofB";
:ライセンス <http://www.wtfpl.net/txt/copying/>;
:依存関係   "POSIX.1-2017".'

set -o errexit; set -o nounset; set -o noclobber
umask 0027
# shellcheck disable=SC2155
export PATH="$(command -p getconf PATH)${PATH:+:$PATH}"
export POSIXLY_CORRECT='200809' UNIX_STD='2003' \
       COMMAND_MODE='unix2003' XPG_SUS_ENV='ON'

# \1   |    \2|     |  \3  |     \4     |   \5 |     
# 76543|210 76|54321|0 7654|3210 7|65432|10 765|43210
# -----|--- --|-----|- ----|---- -|-----|-- ---|-----
# xxxxx|xxx xx|xxxxx|x xxxx|xxxx x|xxxxx|xx xxx|xxxxx
#
# 7 : 255 | 3 : 15
# 6 : 127 | 2 :  7
# 5 :  63 | 1 :  3
# 4 :  31 | 0 :  1
#
# 16 8 4 2 1
# x  x x x x

{ { ${1+:} false && printf '%s' "$1"; } || cat; } | # <a>
{ echo; od -v -A n -t x1; } | # <1>
{ tr -s '[:blank:]' '\n'; printf '\n\n\n\n'; } | # <2>
sed -e '1d;2i\
set -- \\\
  0 1 2 3 4 5 6 7 8 9 A B C D E F \\\
  G H J K M N P Q R S T V W X Y Z \
eval echo \\
H;N;H;N;H;N;H;N
s/'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)/"'\
'\\${$(((0x\1 >>  3) + 1))}'\
'\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}'\
'\\${$((((0x\2 >>   1) \& 31) + 1))}'\
'\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}'\
'\\${$(((0x\3 \& 15) *  2 + (0x\4 >> 7) + 1))}'\
'\\${$((((0x\4 \& 127) >>  2) + 1))}'\
'\\${$(((0x\4 \&  3) *  8 + (0x\5 >> 5) + 1))}'\
'\\${$(((0x\5 \& 31) + 1))}"\\/;t
s/'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)/"'\
'\\${$(((0x\1 >>  3) + 1))}'\
'\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}'\
'\\${$((((0x\2 >>   1) \& 31) + 1))}'\
'\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}'\
'\\${$(((0x\3 \& 15) *  2 + (0x\4 >> 7) + 1))}'\
'\\${$((((0x\4 \& 127) >>  2) + 1))}'\
'\\${$(((0x\4 \&  3) *  8 + 1))}"/;t
s/'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)/"'\
'\\${$(((0x\1 >>  3) + 1))}"'\
'\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}"'\
'\\${$((((0x\2 >>   1) \& 31) + 1))}"'\
'\\${$(((0x\2 \&  1) * 16 + (0x\3 >> 4) + 1))}"'\
'\\${$(((0x\3 \& 15) *  2 + 1))}"/;t
s/'\
'\([[:xdigit:]]\{2\}\)\n'\
'\([[:xdigit:]]\{2\}\)/"'\
'\\${$(((0x\1 >>  3) + 1))}'\
'\\${$(((0x\1 \&  7) *  4 + (0x\2 >> 6) + 1))}'\
'\\${$((((0x\2 >>   1) \& 31) + 1))}'\
'\\${$(((0x\2 \&  1) * 16 + 1))}"/;t
s/'\
'\([[:xdigit:]]\{2\}\)/"'\
'\\${$(((0x\1 >>  3) + 1))}'\
'\\${$(((0x\1 \&  7) *  4 + 1))}"/' |
sh

実装上の註釈

<0:1バイトあたりのビット数およびバイト順>: 可搬運用機構界面で1バイトは正確に8ビットであると定められているため,「1バイトごとに切り分ける」処理を「8ビットごとに切り分ける」処理と同一視してよい。また,バイトは,その名前から明らかではあるが,1バイトごとの切り出しにおいては考慮の必要がない。

<1>: od用類にバイト位置を印刷しないよう指示した場合 (-A n) の出力において,各行の先頭に[:blank:]文字が付けられるのかは定められていない。そこで,本体の直前に改行文字を挿入することで,tr用類などによる処理ののちに,元のod用類の出力がどのような形式であっても,常にかならず一つの改行文字が入力先頭に存在するようにしてこの問題を対処した。

<2>: sed用類のN命令は次行がないと(つまり入力終端において)当該sed即譜の全体の処理を(即座に)終了する。本体の出力後に改行文字を$5 - 1 = 4$個付け足すことで,sed譜における(5回にわたる)次行の読み取りと処理領域への格納とが,本体の終端までに失敗(してsed即譜の処理が終了)することがなくなった。本体の終端判定およびそれに対する処理は,sed用類における置換成否判定を利用した分岐(t命令)によって行う。

<0:「eval echo」行> 「eval echo」行は出力先頭にただ一度だけ挿入する。こうすることで残りの全ての出力が単一のeval echoに対する(しばしば非常に長い)引数となる。引数が十分に長くなりうる場合には,その全長がARG_MAXの値を越えることを考慮しなければならないが,ARG_MAX値が存在するのはexec函数の実行時のみである。換言すれば,仕類の組込命令では,引数の長さが事実上無制限であるとしてよい。現行のほとんどすべての仕類実装において!!!また,sh用類に対する入力は行長の制限がないので,こちらの実行も問題はない。

<a>: 命令行の引数を既定の入力元とし,もしそれが空なら標準入力を入力とする。

{高位}{下位}{ビット}{情報収体}{バイト}{ISO/IEC 9899:1999}=}(6)

{POSIXにおけるバイト K#9-D657/A-6234}

https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_84

個別に番地付け可能な情報収体の単位で,正確に8ビットであり,文字または文字の一部を格納するのに用いられる; POSIXにおける文字も参照。
バイトを構成するのは8ビットの連続列である。
最も小さい有効ビットは「下位」,最も大きい有効ビットは「高位」と呼ばれる。

注意:: The definition of byte from the 国際標準化機構によるC標準 is broader than the above and might accommodate hardware architectures with different sized addressable units than octets.

{高位}=}(1)
{下位}=}(1)
{保管域}{情報}=}(2)
{保管}{ストレージ}=}(2)
{}