shell实现面向对象编程

今天看到一篇博客, 有人实现了 shell 的面向对象功能. 虽然class new 等是用函数实现的, 但是思想非常巧妙, 很有意思, 所以就把它贴在这里, 记录一下.
而且看起来还不是很容易弄明白, 可以打开 set -x 配合源码一起看.

其中使用到了 uuidgen, 依赖于系统中的 uuid-runtime. 如果没有安装, 请安装对应的库, ubuntu中的命令是:

1
apt install uuid-runtime

原文地址: https://coolshell.cn/articles/5035.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/bin/bash

#---------------------------------
# OO support functions
#---------------------------------
#set -x

DEFCLASS=""
CLASS=""
THIS=0

class() {
DEFCLASS="$1"
eval CLASS_${DEFCLASS}_VARS=""
eval CLASS_${DEFCLASS}_FUNCTIONS=""
}

static() {
return 0
}

func() {
local varname="CLASS_${DEFCLASS}_FUNCTIONS"
eval "$varname=\"\${$varname}$1 \""
}

var() {
local varname="CLASS_${DEFCLASS}_VARS"
eval $varname="\"\${$varname}$1 \""
}

loadvar() {
eval "varlist=\"\$CLASS_${CLASS}_VARS\""
for var in $varlist; do
eval "$var=\"\$INSTANCE_${THIS}_$var\""
done
}

loadfunc() {
eval "funclist=\"\$CLASS_${CLASS}_FUNCTIONS\""
for func in $funclist; do
eval "${func}() { ${CLASS}::${func} \"\$@\"; return \$?; }"
done
}

savevar() {
eval "varlist=\"\$CLASS_${CLASS}_VARS\""
for var in $varlist; do
eval "INSTANCE_${THIS}_$var=\"\$$var\""
done
}

typeof() {
eval echo \$TYPEOF_$1
}

new() {
local class="$1"
local cvar="$2"
shift
shift
local id=$(uuidgen | tr A-F a-f | sed -e "s/-//g")
eval TYPEOF_${id}=$class
eval $cvar=$id
local funclist
eval "funclist=\"\$CLASS_${class}_FUNCTIONS\""
for func in $funclist; do
eval "${cvar}.${func}() {
local t=\$THIS; THIS=$id; local c=\$CLASS; CLASS=$class; loadvar;
loadfunc; ${class}::${func} \"\$@\"; rt=\$?; savevar; CLASS=\$c;
THIS=\$t; return $rt;
}"
done
eval "${cvar}.${class} \"\$@\" || true"
}



#---------------------------------------------------
# Example code
#---------------------------------------------------

# class definition
class Storpel
func Storpel
func setName
func setQuality
func print
var name
var quality

# class implementation
Storpel::Storpel() {
setName "$1"
setQuality "$2"
if [ -z "$name" ]; then setName "Generic"; fi
if [ -z "$quality" ]; then setQuality "Normal"; fi
}

Storpel::setName() { name="$1"; }
Storpel::setQuality() { quality="$1"; }
Storpel::print() { echo "$name ($quality)"; }

#usage
new Storpel one "Storpilator 1000" Medium
new Storpel two
new Storpel three
#
two.setName "Storpilator 2000"
two.setQuality "Strong"

one.print
two.print
three.print

echo ""
echo "one: $one ($(typeof $one))"
echo "two: $two ($(typeof $two))"
echo "Three: $three ($(typeof $three))"