Shell编程-2

代码实现如下:

shell

# 解析 yml , 数组自动添加序号
# 
### 例如:
### yml 如下:
### global:
###   input:
###     - "main.c"
###     - "main.h"
###   flags: [ "-O3", "-fpic" ]
###   sample_input:
###     -  { property1: value, property2: "value2" }
###     -  { property1: "value3", property2: 'value 4' }
### 
### 执行: eval $(parse_yaml "config.yml")
###
### 解析结果如下,相当于生成了如下代码:
### global_input_1="main.c"
### global_input_2="main.h"
### global_flags_1="-O3"
### global_flags_2="-fpic"
### global_sample_input_1_property1="value"
### global_sample_input_1_property2="value2"
### global_sample_input_2_property1="value3"
### global_sample_input_2_property2="value 4"
### 
### 最后可以使用间接变量引用,访问变量
###
function parse_yaml {
   local prefix=$2
   local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo -e '\034')
   sed -ne "s|,$s\]$s\$|]|" \
        -e ":1;s|^\($s\)\($w\)$s:$s\[$s\(.*\)$s,$s\(.*\)$s\]|\1\2: [\3]\n\1  - \4|;t1" \
        -e "s|^\($s\)\($w\)$s:$s\[$s\(.*\)$s\]|\1\2:\n\1  - \3|;p" $1 | \
   sed -ne "s|,$s}$s\$|}|" \
        -e ":1;s|^\($s\)-$s{$s\(.*\)$s,$s\($w\)$s:$s\(.*\)$s}|\1- {\2}\n\1  \3: \4|;t1" \
        -e    "s|^\($s\)-$s{$s\(.*\)$s}|\1-\n\1  \2|;p" | \
   sed -ne "s|^\($s\):|\1|" \
        -e "s|^\($s\)-$s[\"']\(.*\)[\"']$s\$|\1$fs$fs\2|p" \
        -e "s|^\($s\)-$s\(.*\)$s\$|\1$fs$fs\2|p" \
        -e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
        -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" | \
   awk -F$fs '{
      indent = length($1)/2;
      vname[indent] = $2;
      for (i in vname) {if (i > indent) {delete vname[i]; idx[i]=0}}
      if(length($2)== 0){  vname[indent]= ++idx[indent] };
      if (length($3) > 0) {
         vn=""; for (i=0; i<indent; i++) { vn=(vn)(vname[i])("_")}
		 gsub(/\s*#.*$/, "", $3);
         printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, vname[indent], $3);
      }
   }'
}

用法:

编码数据的格式

程序通常(至少)使用两种形式的数据:

  1. 内存中,数据存储在对象、结构体、列表、数组、散列表、树等中。这些数据结构针对CPU的高效访问和操作做了优化(通常使用指针)。
  2. 如果要将数据写入文件,或者通过网络发送,则必须将其 编码(encode) 为某种自包含的字节序列(如:json文档)。由于每个进程都有自己的独立的地址空间,一个进程中的指针对任何其他进程都没有意义,所以这个字节序列表示 与 通常在内存中使用的数据结构完全不同 (除了一些特殊情况外,如某些内存映射文件或直接压缩数据上的操作)

所以,两者表示之间,需要进行某种类型的翻译。

模式与兼容

修改应用程序的功能也也意味着修改其存储的数据:使用新的字段或记录类型,或者以新的方式展示现有的数据。

不同的数据模型有不同的方法应对这种变化:

  • 关系型数据库假定数据库中的所有数据都遵循一个模式:尽管可以更改这个模式(通过模式迁移,即 ALTER 语句),但是在任何时间点都有且仅有一个正确的模式。
  • 读时模式(schema-on-read,或 无模式,即 schemaless)数据库不会强制一个模式,因此数据库可以包含在不同时间写入的新老数据格式的混合。

当数据 格式(format)模式(schema) 发生变化时,通常需要对应用程序代码进行相应的更改(例如,为记录添加新字段,然后修改程序开始读写该字段)。但在大型应用程序中,代码变更通常不会立即完成:

OLTP-or-OLAP

属性事务处理系统 OLTP (OnLine Transaction Processing)分析系统 OLAP (OnLine Analytice Processing)
主要读取模式查询少量记录,按键读取在大批量记录上聚合
主要写入模式随机访问,写入要求低延时批量导入(ETL)或者事件流
主要用户终端用户,通过 Web 应用内部数据分析师,用于决策支持
处理的数据数据的最新状态(当前时间点)随时间推移的历史事件
数据集尺寸GB ~ TBTB ~ PB

起初,事务处理和分析查询使用了相同的数据库。 SQL 在这方面已证明是非常灵活的:对于 OLTP 类型的查询以及 OLAP 类型的查询来说效果都很好。尽管如此,在二十世纪八十年代末和九十年代初期,企业有停止使用 OLTP 系统进行分析的趋势,转而在单独的数据库上运行分析。这个单独的数据库被称为 数据仓库(data warehouse)

BitMap

使用一个 bit 位来存储某种状态(比如签到与否,是否存在等)。

如记录 0-7 这几个数字中哪些存在,只需要 8 个 bit 位。0 表示数字不存在,1 表示数字存在,1,2,3,5 这几个数存在, 存储如下:

Shell编程-1

shell

# 单引号:原样, 双引号:会解析变量
a=1 # = 两边不加空格
str_1='a=$a' # a=$a
str_2="a=$a" # a=1

str_3=`pwd` # `(反引号)内的字符串被当作shell命令,执行完结果返回给 str_3 

# 字符串长度
s='abcd'
len=${#s} # 等价于 ${#s[0]}

# 截取 从第1个字符开始,截取3个字符,索引从0开始
sub_s=${s:1:3}