最大熵模型

逻辑斯蒂回归

逻辑斯蒂分布

  • $\mu$:位置参数
  • $\gamma$:形状参数
  • 分布函数属于逻辑斯蒂函数
  • 分布函数图像为sigmoid curve

    • 关于的$(\mu, \frac 1 2)$中心对称
    • 曲线在靠近$\mu$中心附近增长速度快,两端速度增长慢
    • 形状参数$\gamma$越小,曲线在中心附近增加越快
  • 模型优点

    • 模型输出值位于0、1之间,天然具有概率意义,方便观测 样本概率分数
    • 可以结合$l-norm$正则化解决过拟合、共线性问题
    • 实现简单,广泛用于工业问题
    • 分类时计算量比较小、速度快、消耗资源少
  • 模型缺点

    • 特征空间很大时,性能不是很好,容易欠拟合,准确率一般
    • 对非线性特征需要进行转换

Binomial Logistic Regression Model

二项逻辑斯蒂回归模型:形式为参数化逻辑斯蒂分布的二分类 生成模型

  • $w, b$:权值向量、偏置
  • $\hat x = (x^T|1)^T$
  • $\hat w = (w^T|b)^T$
  • 逻辑回归比较两个条件概率值,将实例$x$归于条件概率较大类

  • 通过逻辑回归模型,可以将线性函数$wx$转换为概率

    • 线性函数值越接近正无穷,概率值越接近1
    • 线性函数值越接近负无穷,概率值越接近0

Odds/Odds Ratio

  • 在逻辑回归模型中,输出$Y=1$的对数几率是输入x的线性函数

  • OR在逻辑回归中意义:$x_i$每增加一个单位,odds将变为原来 的$e^{w_i}$倍

    • 对数值型变量

      • 多元LR中,变量对应的系数可以计算相应 Conditional OR
      • 可以建立单变量LR,得到变量系数及相应 Marginal OR
    • 对分类型变量

      • 可以直接计算变量各取值间对应的OR
      • 变量数值化编码建立模型,得到变量对应OR
      • 根据变量编码方式不同,变量对应OR的含义不同,其中 符合数值变量变动模式的是WOE线性编码

策略

极大似然:极小对数损失(交叉熵损失)

  • $\pi(x) = P(Y=1|x)$

算法

  • 通常采用梯度下降、拟牛顿法求解有以上最优化问题

Multi-Nominal Logistic Regression Model

多项逻辑斯蒂回归:二项逻辑回归模型推广

  • 策略、算法类似二项逻辑回归模型

Generalized Linear Model

todo

Maximum Entropy Model

最大熵原理

最大熵原理:学习概率模型时,在所有可能的概率模型(分布)中, 熵最大的模型是最好的模型

  • 使用约束条件确定概率模型的集合,则最大熵原理也可以表述为 在满足约束条件的模型中选取熵最大的模型

  • 直观的,最大熵原理认为

    • 概率模型要满足已有事实(约束条件)
    • 没有更多信息的情况下,不确定部分是等可能的
    • 等可能不容易操作,所有考虑使用可优化的熵最大化 表示等可能性

最大熵模型

最大熵模型为生成模型

  • 对给定数据集$T={(x_1,y_1),\cdots,(x_N,y_N)}$,联合分布 P(X,Y)、边缘分布P(X)的经验分布如下

    • $v(X=x,Y=y)$:训练集中样本$(x,y)$出频数
  • 用如下feature function $f(x, y)$描述输入x、输出y之间 某个事实

    • 特征函数关于经验分布$\tilde P(X, Y)$的期望

    • 特征函数关于生成模型$P(Y|X)$、经验分布$\tilde P(X)$ 期望

  • 期望模型$P(Y|X)$能够获取数据中信息,则两个期望值应该相等

    此即作为模型学习的约束条件

    • 此约束是纯粹的关于$P(Y|X)$的约束,只是约束形式特殊, 需要通过期望关联熵

    • 若有其他表述形式、可以直接带入的、关于$P(Y|X)$约束, 可以直接使用

  • 满足所有约束条件的模型集合为 定义在条件概率分布$P(Y|X)$上的条件熵为 则模型集合$\mathcal{C}$中条件熵最大者即为最大是模型

策略

最大熵模型的策略为以下约束最优化问题

  • 引入拉格朗日函数

    • 原始问题为

    • 对偶问题为

    • 考虑拉格朗日函数$L(P, w)$是P的凸函数,则原始问题、 对偶问题解相同

  • 求$L(P, w)$对$P(Y|X)$偏导

    偏导置0,考虑到$\tilde P(x) > 0$,其系数必始终为0,有

  • 考虑到约束$\sum_y P(y|x) = 1$,有

    • $Z_w(x)$:规范化因子
    • $f(x, y)$:特征
    • $w_i$:特征权值
  • 原最优化问题等价于求解偶问题极大化问题$\max_w \Psi(w)$

    记其解为

    带入即可得到最优(最大熵)模型$P_{w^{*}}(Y|X)$

策略性质

  • 已知训练数据的经验概率分布为$\tilde P(X,Y)$,则条件概率 分布$P(Y|X)$的对数似然函数为

    • 这里省略了系数样本数量$N$
  • 将最大熵模型带入,可得

    对偶函数$\Psi(w)$等价于对数似然函数$L_{\tilde P}(P_w)$, 即最大熵模型中,对偶函数极大等价于模型极大似然估计

改进的迭代尺度法

  • 思想

    • 假设最大熵模型当前参数向量$w=(w_1,w_2,\cdots,w_M)^T$
    • 希望能找到新的参数向量(参数向量更新) $w+\sigma=(w_1+\sigma_1,\cdots,w_M+\sigma_M)$ 使得模型对数似然函数/对偶函数值增加
    • 不断对似然函数值进行更新,直到找到对数似然函数极大值
  • 对给定经验分布$\tilde P(x,y)$,参数向量更新至$w+\sigma$ 时,对数似然函数值变化为

    • 不等式步利用$a - 1 \geq log a, a \geq 1$

    • 最后一步利用

  • 记上式右端为$A(\sigma|w)$,则其为对数似然函数改变量的 一个下界

    • 若适当的$\sigma$能增加其值,则对数似然函数值也应该 增加
    • 函数$A(\sigma|w)$中因变量$\sigma$为向量,难以同时 优化,尝试每次只优化一个变量$\sigma_i$,固定其他变量 $\sigma_j$
  • 考虑到$f_i(x,y)$为二值函数,则$f^{**}(x,y)$表示所有特征 在$(x,y)$出现的次数,且有

  • 考虑到$\sum_{i=1}^M \frac {f_i(x,y)} {f^{**}(x,y)} = 1$, 由指数函数凸性、Jensen不等式有

  • 记上述不等式右端为$B(\sigma|w)$,则有

    其为对数似然函数改变量的一个新、相对不紧的下界

  • 求$B(\sigma|w)$对$\sigma_i$的偏导

    置偏导为0,可得

    其中仅含变量$\sigma_i$,则依次求解以上方程即可得到 $\sigma$

算法

  • 输入:特征函数$f_1, f_2, \cdots, f_M$、经验分布 $\tilde P(x)$、最大熵模型$P_w(x)$
  • 输出:最优参数值$wi^{*}$、最优模型$P{w^{*}}$
  1. 对所有$i \in {1,2,\cdots,M}$,取初值$w_i = 0$

  2. 对每个$i \in {1,2,\cdots,M}$,求解以上方程得$\sigma_i$

    • 若$f^{**}(x,y)=C$为常数,则$\sigma_i$有解析解

    • 若$f^{**}(x,y)$不是常数,则可以通过牛顿法迭代求解

      • $g(\sigma_i)$:上述方程对应函数
      • 上述方程有单根,选择适当初值则牛顿法恒收敛
  3. 更新$w_i$,$w_i \leftarrow w_i + \sigma_i$,若不是所有 $w_i$均收敛,重复2

BFGS算法

对最大熵模型

  • 为方便,目标函数改为求极小

  • 梯度为

算法

将目标函数带入BFGS算法即可

  • 输入:特征函数$f_1, f_2, \cdots, f_M$、经验分布 $\tilde P(x)$、最大熵模型$P_w(x)$
  • 输出:最优参数值$wi^{*}$、最优模型$P{w^{*}}$
  1. 取初值$w^{(0)}$、正定对称矩阵$B^{(0)}$,置k=0

  2. 计算$g^{(k)} = g(w^{(k)})$,若$|g^{(k)}| < \epsilon$, 停止计算,得到解$w^{*} = w^{(k)}$

  3. 由拟牛顿公式$B^{(k)}p^{(k)} = -g^{(k)}$求解$p^{(k)}$

  4. 一维搜索,求解

  5. 置$w^{(k+1)} = w^{(k)} + \lambda^{(k)} p_k$

  6. 计算$g^{(k+1)} = g(w^{(k+1)})$,若 $|g^{(k+1)}| < \epsilon$,停止计算,得到解 $w^{*} = w^{(k+1)}$,否则求

    • $s^{(k)} = w^{(k+1)} - w^{(k)}$
    • $y^{(k)} = g^{(k+1)} - g^{(k)}$
  7. 置k=k+1,转3

Vim 配置

打印信息

  • :echo:打印信息,但是信息不会保存
  • :echom:打印信息会保存在:messages
  • :messages:查看:echom保存的信息

设置选项

  • 设置选项方式

    • 命令行一次设置多个选项::set number numberwidth=6
    • 本地缓冲区设置::setlocal nonumber
  • 设置 bool 选项

    • :set <name>:打开选项
    • :set no<name>:关闭选项
    • :set <name>!:切换选项
    • :set <name>?:查看选项值(返回或no
  • 设置键值选项

    • :set <name>=value:设置选项值
    • :set <name>?:查看选项值
    • 键值选项支持运算:+=

statusline 状态栏设置

  • 状态栏代码通用格式:%-0{minwid}.{maxwid}{item}

    • -:左对齐
    • 0:使用”0”填充
    • %=:切换到状态栏右侧

    • %f:文件名

    • %F:完整路径文件名
    • %y:文件类型([text],[python])
    • %Y:文件类型(TEXT,PYTHON)

    • %l:当前行号

    • %L:总行数
    • %v/%V:列号
    • %c:字符列号
    • %p:文件位置百分比

    • %n:buffer number

    • %{&ff}:文件格式(DOS、UNIX)
    • %b:当前字符ACSII码
    • %B:当前字符16进制值
    • %m:modified flag([+],[-]表示不可修改)
  • 设置状态栏显式格式,既可以一行完成配置,也可以分开配置

    1
    2
    3
    4
    5
    6
    set statusline=%f\ -\ filetype:\ %y
    set statusline=%f
    set statusline+=%=
    set statusline+=%l
    set statusline+=/
    set statusline+=%L
    • 中间空格需要用“\“转义,“%%”转义“%”
  • laststatus:设置状态栏显示模式

    • 1:默认值,两个以上窗口才显示
    • 2:一直显示

折叠设置

  • foldmethod
    • manual:手动折叠选中的行(默认 zf 触发)
    • marker{{{` 到 `}}} 标记待折叠行(默认 za 触发)
    • indent:折叠缩进
    • syntax:语法折叠
  • foldlevel=<num>:设置 indent 折叠起始水平(zm 触发),即从 <num> 水平开始尝试折叠
  • foldlevelstart=<num>:设置文件打开时默认折叠水平
    • -1:初始不折叠
  • foldcolumn=<num>:用 <num> 行表示可可折叠状态

一些常用关键字

  • iskeyword=@,_,48-57,192_255:指定关键字

    • 下划线
    • ASCII 码位在 48-57 之间的字符(0-9)、192-255之间的字符
  • conceallevel=0:隐藏等级

    • 1
    • 2

键盘映射

1
:<mode>map <mark> {lhs} {rhs}
  • 注意:映射后不能跟注释,vim会认为整行都是命令

映射工作模式

  • 映射的工作模式可区分 6 种
    • normal 模式:输入命令时
    • visual 模式:可视区域高亮并输入命令时
    • select 模式:类似可视模式,但键入的字符对选择区替换
    • operator-pending 模式:操作符等待中
    • insert 模式:包括替换模式
    • command-line 模式:输入 :/ 命令时

映射命令设置

  • 映射命令设置的模式如下,对应都有如下非递归、取消命令

    • <mode>noremap[!]:非递归映射,即不会在其他映射中再次被展开
    • <mode>unmap[!]:取消映射
    • <mode>mapclear[!]

    |命令|模式| |——-|——-| |:map|normalvisualselectoperator-pending| |:nmap|normal| |:vmap|visualselect| |:smap|selection| |:xmap|visual| |:omap|operator-pending| |:map!|insertcommand-line| |:imap|insert| |:lmap|insertcommand-lineLang-Arg| |:cmap|command-line| |:tmap|终端作业|

特殊参数

  • 映射特殊参数

    • <buffer>:映射将局限于当前缓冲区
      • 优先级比全局映射高
      • 清除映射时同样需要添加参数
      • 可使用 <leader> 替代 <localleader> 可工作,但是不推荐
    • <nowait>:存在较短映射时,失效以其作为前缀的较长映射
    • <silent>:映射不在命令行上回显
    • <special>:特殊键可以使用<>记法
    • <script>:映射只使用通过以<SID>开头来定义的脚本局部映射来重映射优右值中的字符
    • <unique>:若存在相同命令、缩写则定义失败
      • 定义局部映射时,同样会检查全局映射
    • <expr>:映射的右值将被作为表达式被计算
  • 特殊参数说明

    • 特殊参数的尖括号<>是本身具有的,必须紧跟命令后面
    • 有些特殊参数在取消映射时同样需注明

omap

  • 应用方法:operator (操作) + operator-pending (移动、范围选择)
  • 预定义的 operator-pending 映射如 wawi(t,

    |按键 |操作 |移动 | |———-|———————-|———————-| |dw |删除(delete) |到下一个单词 | |ci( |修改(change) |在括号内 | |yt, |复制 |到逗号前 |

  • 自定义的 operator-pending 映射则需要

    • 选取一定范围:可同时指定开头、结尾(一般通过进入 visual 模式下选择范围)

      1
      2
      3
      4
      5
      6
      7
      " 下个括号内内容
      onoremap in( :<c-u>normal! f(vi(<cr>
      " 当前括号内容
      onoremap il( :<c-u>normal! f)vi(<cr>`
      " 选取使用 `===` 标记 markdown 标题
      onoremap ih :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>
      onoremap ah :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rg_vk0"<cr>
    • 指定光标位置:光标当前位置为开头、指定位置为结尾

      1
      2
      " 移动至 `return` 前一行
      onoremap b /return<cr>

leaderslocalleader

leaderlocalleader:作为“前缀”的不常用的按键,后接其他字符作为整体映射

  • 用途

    • 避免覆盖太多按键原始功能
    • 约定俗成的规范,容易理解
    • 方便更改 <leader><localleader> 作为前缀设置
      • <leader>:对全局映射而设置的映射的前缀
      • <localleader>:只对某类(个)文件而设置的映射的前缀
    • <leader><localleader> 除了设置不同以外,没有太大区别,应用场合时约定规范,不是强制性的
  • <leader><localleader> 设置

    1
    2
    3
    4
    :let mapleader = "-"
    :nnoremap <leader>d dd
    :let maplocalleader = "\\"
    :nnoremap <buffer> <localleader>c I#<esc>
    • vim 会对 mapleadermaplocalleader 进行特殊的处理,不是简单的声明

Abbreviations 缩写

  • iabbrev:紧跟缩写输入非关键字后,缩写会替换为相应的完整字符串
    • 相较于映射
      • iabbrev 用于 insertreplacecommand-line 模式
      • iabbrev 会注意缩写前后的字符,只在需要的时候替换
    • iabbrev 同样支持特殊参数
      • <buffer>:仅限本地缓冲区
1
2
3
4
5
6
7
8
" 纠错
iabbrev waht what
" 简化输入
iabbrev @@ xyy15926@gmail.com
" 替换 `----` 为前个单词
iabbrev <buffer> ---- &mdash
" 替换 `return` 为 null
iabbrev <buffer> return nopenopenope
  • :set iskeyword? 即可查看关键字字符

Autocmd 自动命令

autocmd 使用

  • autocmd 注意事项

    • 同时监听多个事件,使用 , 分隔,中间不能有空格
    • 一般同时监听 bufnewfilebufread,这样打开文件时无论文件是否存在都会执行命令
    • 所有事件后面都需要注明适用场景,可用*表示全部场景,中间也不能有空格
    • autocmd 是定义命令,不是执行命令
      • 每次执行都会定义命令,而vim 不会忽略重复定义
      • 如::autocmd bufwrite * :sleep 200m,每次执行时都会重复定义命令
  • 缓冲区事件

    1
    2
    3
    4
    autocmd bufnewfile * :write
    autocmd bufnewfile *.txt :write
    autocmd bufwritepre *.html :normal gg=g
    autocdm bufnewfile,bufread *.html setlocal nowrap
  • filetype 事件(vim 设置缓冲区 filetype 时触发)

    1
    2
    3
    4
    autocmd filetype javascript nnoremap <buffer> <localleader>c i//<esc>
    autocmd filetype python nnoremap <buffer> <localleader>c i#<esc>
    autocmd filetype javascript :iabbrev <buffer> iff if ()<left>
    autocmd filetype python :iabbrev <buffer> iff if:<left>

augroup 自动命令组

  • 自动命令组

    1
    2
    3
    4
    augroup cmdgroup
    autocmd bufwrite * :echom "foo"
    autocmd bufwrite * :echom "bar"
    augroup end
  • 注意事项

    • 类似 autocmdvim 不会忽略重复定义,但是可以通过 :autocmd! 清除一个组

      :augroup cmdgroup : autocmd! : autocmd bufwrite :echom “foo” : autocmd bufwrite :echom “bar” :augroup end

Vim安装

安装选项

1
2
3
4
5
6
7
8
$ ./configure --with-features=huge\
--enable-multibyte \
--enable-python3interp \
--with-python3-config-dir=/usr/lib64/python3.4/config-3.4m/ \
--enable-pythoninterp \
--with-python-config-dir=/usr/lib64/python2.7/config/ \
--prefix=/usr/local
--enable-cscope
  • 按照以上命令配置,编译出的Vim版本中是动态支持 +python/dyn+python3/dyn

  • 此时Vim看似有python支持,但是在Vim内部 :echo has("python"):echo has("python3")都返回0

  • 之后无意中尝试去掉对python的支持,编译出来的Vim就是 可用的python3,不直到为啥

Vim KeyMapper CMD

Vim模式

Normal模式

Insert模式

Visual模式

Quickfix模式

quickfix模式主要思想时保存一个位置列表,然后提供一系列命令, 实现在这个位置列表中的跳转

  • 位置列表来源

    • 编译器输出信息
    • grep命令输出信息(cscope命令)
    • :vimgrep命令
  • quickfix中常用的命令有

    • :copen/:cw:打开quickfix模式窗口
    • :cclose:关闭quickfix窗口
    • :cc:显示详细错误信息
    • :cp:跳至下一个错误
    • :cn:跳至上一个错误
    • :cl:列出所有错误
    • :cw:如果有错误列表,则打开quickfix窗口
    • :colder/col:到前一个旧错误列表
    • :cnewer/cnew:到后一个新错误列表

Ex模式

底层编辑模型,normal下Q进入

Paste模式

Motion快捷键

normal模式下移动,visual模式下选取,无特殊说明visual和normal 模式通用

固定移动

基本

  • hjkl:左、上、下、右
  • gj/gk:虚上、虚下(光标移动排版意义上行) (可以尝试noremap交换和j/k的逻辑方便使用)
  • M:窗口中间行首各非空白字符
  • H/L:窗口顶/底scrolloff处行首各非空白字符
  • <c-i>/<c-o>:跳至下一个/上一个编辑处 (可以跨文件)

行内

  • w:下个单词开头
  • aw:整个单词
  • b/e:当前单词首/尾
  • W/B:下/上个非空格开头
  • E: 下个非空格结尾
  • g_:行尾,visual模式下不包括换行符
  • $:行尾,visual模式下包括换行符
  • 0:行首
  • ^:非空白字符行首
  • |:当前行第一列
  • <int>|:当前行第n列(不是字符)

全文

  • gg:文件首
  • G:文件尾
  • <int>G:第<int>
  • '<:之前visual模式选取起始行(一直保存直至下次选取)
  • '>:之前visual模式选取结束行
  • {/}:下/上一个空行
  • .:当前行
  • %:全文选取???

组合

这些快捷键的效果取决于当前状态

行内

  • f/F:向前/后移动到某字符(;,同向、反向重复)
  • t/T:till,向前/后移动到某字符前
  • i:在某个区域((), [], {}, w等)内(显然不能单独用 于normal)

全文

  • //?:命令行向前、向后查找(nN同向、反向重复)
  • */#:向前、向后查找当前单词
  • g*/g#:向前、向后查找当前字符串,包括非单独单词

Operation快捷键

区域进行操作可以和motion连用

内容修改

插入

  • i:insert进入insert模式
  • I(normal):行首insert进入insert模式
  • I(visual block):选中区域同时插入
  • a:add进入insert模式
  • A:行尾add进入insert模式
  • <c-e>:insert模式下复制下行当前位置字符至当前行

删除

  • d:删除选取区域
  • c:删除(修改)选中区域,进入insert模式
  • x/X:删除当前/前一个字符
  • s:删除字符,进入insert模式
  • dd:删除当前行
  • D:normal模式删除当前位置至行尾
  • <c-h>/<m-h>:insert模式backspace

复制、粘贴

  • ["<reg>]y:复制选中区域至寄存器<reg>,默认 "<reg>
  • yy:复制当前行
  • ["<reg>]p:粘贴"<reg>寄存器中内容,默认"<reg>

其他

  • J:合并下一行,<space>分隔
  • u/U(visual):转换为小、大写
  • ~(normal):当前字符大、小写切换(光标移动至下个字符)
  • ~(visual):选中区域大、小写切换
  • gu/gU(normal)区域转换为小、大写
  • g~区域大、小写切换
  • [num]>/<:右/左移动区域num个shiftwidth单位
  • =区域格式化(修改为标准缩进)
  • <c-d>/<c-i>:insert模式减少/增加缩进
  • gc(visual/normal):选中区域按行注释/取消注释 (应该是按vim的filetype确定注释格式)
  • <c-a>/<c-x>:将光标下数字增加/减少1,支持多种进制

功能性

记录

  • q<reg>:宏记录,记录行为于寄存器<reg>中,按下q则 停止记录
  • @<reg>:调用寄存器<reg>中的宏操作(不一定是q<reg> 记录的结果)
  • m<char>:记录当前位置于<char>中(不是寄存器中未知)
  • `\:回到<char>中记录的位置

撤销、redo

  • .:重复上一个操作
  • u:撤销上一个操作
  • <c-r>:继续执行,撤销u
  • <c-m>:等同于<cr>

外部功能

  • K:对当前单词调用keywordprg设置的外部程序,默认“man”

Diff

  • ]c/[c:比较窗口中移至下个不同的为止
  • do/dp:将当前比较窗口中不同区域,同步为/至另一个 窗口该位置

其他

  • q::vim命令历史窗口

界面变动

窗口

Window

  • <c-w-h/j/k/l>:切换至左/下/上/右窗口
  • <c-w-w>:轮换窗口(切换活动窗口)
  • <c-w-t/b/p>:切换至最左上/右下/前个窗口
  • <c-w-+/->:竖直方向扩展/收缩当前窗口
  • <c-w->/<>:水平方向扩展/收缩当前窗口
  • <c-w-=>:恢复当前窗口高度
  • <c-w-H/J/K/L>:移动窗口至tab左/下/上/右,占据全部高/宽
  • <c-w-T>:移动窗口至新tab
  • <c-w-r/x>:交换窗口位置(具体逻辑未知)
  • ZZ:保存退出
  • ZQ:放弃保存退出

Tab

  • [n]gt/gT:下/上一个tab;第n个tab

内容

折叠

  • foldmethod=marker{{{`、`}}}标记折叠区域(各花括号之间无空格)

    • zf:创建折叠(在选中区域前后添加标记)
      • zf[n]G:创建当前行至第n行折叠
      • [n]zf[+]:创建当前行至后n行折叠
      • [n]zf[-]:创建当前行至前n行折叠
    • zd:删除 包含 当前位置折叠
    • zD递归 删除包含当前位置折叠、及子折叠
    • zE:删除窗口中所有折叠
    • za:折叠 toggle
    • zo:折叠展开
    • zc:折叠
  • foldmethod=indent:缩进标记折叠

    • zc:折叠
    • zC递归 折叠
    • zo:展开折叠
    • zO:递归展开折叠
    • [z:移至当前折叠开始
    • ]z:移至当前折叠末尾
    • zj:移至下个折叠开始(包括关闭折叠)
    • zk:移至上个折叠结束(包括开闭折叠)
    • zm:提高折叠水平,即依次折叠当前最高水平缩进
    • zr:降低折叠水平,即依次展开当前最高水平缩进
    • zn:禁用折叠
    • zN:启用折叠
  • foldmethod=manual:手动折叠

    • zf<range>:折叠选中区域
      • zf70j:折叠之后70行
      • zfa(:折叠 ( 包围区域
  • mkview:保存折叠状态

  • loadview:载入折叠状态

Vim Cmd常用命令

内容相关

查找

//?

:/foo向下查找,:?foo向上查找

  • set ingorecase时,不敏感查找;set smartcase时,如果 查找中有大写字符则敏感;
  • :/foo\c手动强制大小写不敏感,:/foo\C强制敏感
  • nN重复同向、反向之前查找
:vimgrep

文件间搜索

1
:vim[grep] /pattern/[g][j] files
  • 选项

    • g:全局匹配(匹配每行全部)
    • j:查找完毕后,进更新quickfix列表,光标不跳转
  • files

    • %:当前文件
    • *:当前目录
    • **/*:仅子目录
    • **/xxxx:当前目录及子目录所有满足xxxx模式文件
    • pattern:满足pattern的文件
global
  • [range]范围(默认整个文件)中查找{pattern},标记 匹配行
  • 对匹配行执行命令{command}(默认print命令)
    • 若标记行在被操作之前已经被删除、移动、合并等而消失, 则不对器执行操作
1
:[range]g[lobal][!]/{pattern}/{command}
  • 选项
    • [!]:对不匹配者执行草在
1
2
3
4
5
6
7
8
9
10
11
12
:g/^/m 0
# 将文件反序
:g/^/+1 d
:%normal jdd
# 删除偶数行
:g/^/d|m.
:%normal jkdd
# 删除奇数行
:g!/aaa/d
# 删除不包含`aaa`行
:g/aaa/"ay
# 复制包含`aaa`行至寄存器`"`

替换

:s
1
:[start,end]s/foo/bar[/i][I][g]
  • 替换区域:默认只替换当前行
    • 手动指定具体行号::2,4s/foo/bar(左闭右开)
    • 特殊符号
      • 全文替换%:%s/foo/bar
      • 第一行^:^,4s/foo/bar
      • 当前行.:.,6s/foo/bar
      • 末尾行$:4,$s/foo/bar
    • visual模式下,手动选择区域命令行自动补全为:'<,'>
  • 替换标志
    • 大小写不敏感/i\c:%s/foo/bar/i:%s/foo\c/bar
    • 大小写敏感/I\C%s/foo/bar/I:%s/foo\C/bar
    • 全局替换/g(替换每行全部模式)::%s/foo/bar/g
      • 默认情况下只替换首个模式:foo,foobar被替换为 bar,foobar
      • 全局替换模式下:foo,foobar被替换为bar,barbar
  • 交互(确认)替换::%s/foo/bar/c,每次替换前会询问
  • 超级变量
    • &:代表被替换模式字串

文本移动

>/<
1
2
:[range]>
:[range]<
  • 范围内文本块右、左移动1个shiftwidth
  • 移动num个shiftwidth添加num个>/<
move
1
:[range]m[ove] [n]
  • 移动范围内行至第[n]
1
2
:m0
# 移动当前行至首行
t
1
:[range]t [n]
  • 复制范围内至第[n]
1
2
:t.
# 复制当前行至下行

文件相关

放弃修改、重新加载、保存

  • :w[rite]:保存此次修改
  • :e!:放弃本次修改(和:q!不同在于不会退出vim)
  • :bufdo e!:放弃vim所有已打开文件修改
  • :e:重新加载文件
  • :e#:当前窗口加上个buffer(反复切换)
  • :bufdo e:重新加载vim所有已打开文件
  • :saveas new_file_name:另存为,不删除原文件
  • :sb[n]:split窗口加载第n个buffer
  • :b[n]:当前窗口加载第n个buffer
  • :n[n]:当前窗口加载下/第n个buffer

Window

  • :sp[lit]:水平分割当前窗口,展示当前文件
  • :vs[plit]:竖直分割当前窗口,展示当前文件
  • :new:水平分割当前窗口,新文件
  • :vnew:竖直分割当前窗口,新文件
  • :sview:水平分割当前窗口,只读[缺省当前]文件
  • :[n]winc >/<:水平方侧扩展/收缩
  • :[n]winc +/-:竖直方向扩展/收缩
  • :res+/-[n]:竖直方向扩展/收缩
  • :vertical res+/-[n]:水平方向扩展/收缩
  • :ressize[n]:高度设置为n单位
  • :vertical res[n]:宽度设置为n单位
  • :q[uit][!]:退出当前窗口
    • !:强制退出,修改不保存
  • :close:关闭当前窗口(不能关闭最后窗口)
  • :only:关闭其他窗口
  • :qa:退出所有窗口
  • :wq:保存、退出当前窗口
  • :x:类似于wq,但是未修改则不写入

注:

  • 水平方向:扩张优先左侧变化,收缩右侧变化
  • 竖直方向:扩展收缩均优先下侧变化

Tab

  • :tabnew [opt] [cmd] [file_name]:打开新tab
  • :tabc:关闭当前tab
  • :tabo:关闭其他tab
  • :tabs:vim cmd区域查看所有打开的tab信息
  • :tabp:查看前一个tab
  • :tabfirst/:tablast:第一个/最后一个tab
  • :tabn [num]:查看下一个/第num个tab

Diff

  • :diffsplit [filename]:上下分割窗口和当前窗口比较

    • 默认同当前文件进行diff
  • :difft:将当前窗口变为比较窗口

    • 若没有其他比较窗口,则没有明显变化
    • 若存在其他比较窗口,则加入比较
  • :diffu[pdate][!]:更新当前比较窗口

    • 比较状态下修改当前文件后,重新生成比较信息
    • !:重新载入文件后更新(外部修改文件)
  • :diffo[!]:关闭当前窗口比较状态

    • !:关闭所有窗口比较状态

Session

  • :mksession[!] <session-file-name>:将当前状态写入 session 文件
  • :source <session-file-name>:载入已有 session 文件

其他

多行语句

“|”管道符可以用于隔开多个命令:echom "bar" | echom "foo"

:vertical

:vertical基本可以用所和窗口有关命令之前,表示左右(分割)

  • :vert split/:vs:左右分割窗口
  • :vert sb[n]:左右分割窗口载入buff[n]
  • :vert diffs file_name:左右分割窗口diffs
  • :vert res +/-[n]:调整窗口大小

其他CMD命令

编辑过程中使用shell

  • :!{shell command}即可直接执行shell命令并暂时跳出vim

    • :r !{shell command}可以将输出结果读取到当前编辑
    • :w !{sheel command}可以将输出结果输出到vim命令行
  • :shell即可暂时进入到shell环境中,$exit即可回到vim中

  • <c-z>暂时后台挂起vim回到shell环境中,$fg即可回到之前 挂起的进程(此时为vim,详见fg命令)

读取结果

  • :read cmd:读取cmd结果至光标下一行
    • :read !date:读取系统date命令结果

交换文件处理

  • 确认需要恢复:直接恢复R

  • 确认丢弃:直接删除D

  • 没有明确目标:只读打开O

  • 比较交换文件、现在文件差别

    • 恢复打开R
    • 另存为其他文件:saveas filname.bak
    • 与当前文件对比:diffsplit filename
  • 一般不会直接Eedit anyway

Vim命令行参数

vim

  • $ vim [filname]:打开一般窗口
    • -r [filename]:常看交换文件(特定文件对应交换文件)
    • -R [filename]:只读方式打开文件
    • -S session-file:打开session的方式启动vim
      • 需要 :mksession[!] <session-file> 先创建 session 文件

vimdiff

  • $ vimdiff [file1] [file2]:打开比较窗口
    • -u:合并模式比较
    • -c:上下文模式比较
  • 后面两个模型可常用于输出重定向至新文件

Loss Function

损失函数

  • 损失函数可以视为模型与真实的距离的度量
    • 因此损失函数设计关键即,寻找可以代表模型与真实的距离的统计量
    • 同时为求解方便,应该损失函数最好应满足导数存在

Surrogate Loss

代理损失函数:用优化方便的损失函数代替难以优化的损失函数,间接达到优化原损失函数的目标

  • 如 0-1 损失难以优化,考虑使用二次损失、交叉熵损失替代

损失函数设计

  • 对有监督学习:真实 已知,可以直接设计损失函数

  • 对无监督学习:真实 未知,需要给定 真实标准

    • NLP:需要给出语言模型
    • EM 算法:熵最大原理

常用损失函数

01_se_ce_hinge_loss

0-1 Loss

  • 0-1 损失函数梯度要么为 0、要么不存在,无法通过梯度下降方法优化 0-1 损失

  • 适用场合

    • 二分类:Adaboost
    • 多分类:Adaboost.M1

Quadratic / Squared Error Loss

  • 平方错误损失函数可导,可以基于梯度下降算法优化损失函数

  • 适用场合

    • 回归预测:线性回归
    • 分类预测:0-1 二分类(根据预测得分、阈值划分)

Logistic SE

  • 平方损失用于二分类时存在如下问题(模型输出无限制)

    • 若模型对某样本非常确信为正例,给出大于1预测值
    • 此时模型会进行不必要、开销较大的优化
  • 考虑对模型输出进行 sigmoid 变换后作为预测值,再应用平方错误损失函数

    • Logistic SE 损失函数曲线对 0-1 损失拟合优于平方损失
    • 但负区间存在饱和问题,损失最大只有 0.5

Cross Entropy

交叉熵损失

  • $y$:样本实际值
  • $f(x)$:各类别预测概率
  • $K$:分类数目
  • 交叉熵损失综合二次损失、logistic SE 优势,以正样本为例

    • 预测值较大时:损失接近 0,避免无效优化
    • 预测值较小时:损失偏导趋近于 -1,不会出现饱和现象
  • $y$ 为 one-hot 编码时实际值时

    • 分类问题仅某分量为 1:此时交叉熵损失同对数损失(负对数极大似然函数)
    • 标签问题则可有分量为 1
  • 适合场合

    • 多分类问题
    • 标签问题

Hinge Loss

  • $y \in {-1, +1}$
  • 合页损失函数:0-1 损失函数的上界,效果类似交叉熵损失函数

    • 要求分类不仅正确,还要求确信度足够高损失才为 0
    • 即对学习有更高的要求
  • 适用场合

    • 二分类:线性支持向量机

收敛速度对比

  • 指数激活函数时:相较于二次损失,收敛速度更快

  • 二次损失对 $w$ 偏导

    • $\sigma$:sigmoidsoftmax 激活函数
    • $z = wx + b$
    • 考虑到 sigmoid 函数输入值绝对值较大时,其导数较小
    • 激活函数输入 $z=wx+b$ 较大时,$\sigma^{‘}(z)$ 较小,更新速率较慢
  • Softmax 激活函数时,交叉熵对 $w$ 偏导

  • 特别的,对 sigmoid 二分类

    • 考虑 $y \in {(0,1), (1,0)}$、$w$ 有两组
    • 带入一般形式多分类也可以得到二分类结果

不常用损失函数

Absolute Loss

绝对损失函数

  • 适用场合
    • 回归预测

Logarithmic Loss

对数损失函数(负对数极大似然损失函数)

  • 适用场合
    • 多分类:贝叶斯生成模型、逻辑回归

Exponential Loss

指数函数函数

  • 适用场合
    • 二分类:前向分步算法

Pseudo Loss

伪损失:考虑个体损失 $(x_i, y_i)$ 如下,据此构造伪损失

  • $h(x_i, y_i)=1, \sum h(x_i, y)=0$:完全正确预测
  • $h(x_i, y_i)=0, \sum h(x_i, y)=1$:完全错误预测
  • $h(x_i, y_i)=1/M$:随机预测(M为分类数目)
  • $w_j$:样本个体错误标签权重,对不同个体分布可不同
  • $f(x, y^{(j)})$:分类器将输入 $x$ 预测为第 $j$ 类 $y^{(j)}$ 的置信度
  • 伪损失函数考虑了预测 标签 的权重分布

    • 通过改变此分布,能够更明确的关注难以预测的个体标签,而不仅仅个体
  • 伪损失随着分类器预测准确率增加而减小

    • 分类器 $f$ 对所有可能类别输出置信度相同时,伪损失最大达到 0.5,此时就是随机预测
    • 伪损失大于 0.5 时,应该将使用 $1-f$
  • 适用场景

    • 多分类:Adaboost.M2

Lexical Analysis

  • python将读取的程序问题转换为Unicode码点
    • 源文件的文本编码可由编码声明指定
    • 默认UTF-8
  • 词法分析器将文件拆分为token
  • 解释器以词法分析器生成的token流作为输入

行结构

逻辑行

逻辑行:逻辑行的结束以NEWLINE token表示

  • 语句不能跨越逻辑行边集,除非其语法允许包含NEWLINE (如复合语句包含多个子语句)
  • 逻辑行可由一个、多个物理行按照明确、隐含行拼接规则 构成

python程序可以分为很多逻辑行

物理行

物理行:以行终止序列结束的字符序列

  • 源文件、字符串中可以使用任何标准平台上行终止序列
    • Unix:\n换行符LF
    • Win:\r\n回车加换行CR LF
    • Macintosh:\r回车CR
  • 输入结束会被作为最后物理行的隐含终止标志
  • 嵌入Python源码字符串应使用标准C传统换行符\n

显式行拼接

显式行拼接:两个、多个物理行使用\拼接为一个逻辑行

  • 物理行以不在字符串、注释内的反斜杠结尾时,将与下行 拼接构成一个单独逻辑行
    • 反斜杠、其后换行符将被删除
  • 以反斜杠结束的行不能带有注释
  • 反斜杠不能用于
    • 拼接注释
    • 拼接字符串外token
  • 不允许原文字符串以外反斜杠存在于物理行其他位置

隐式行拼接

隐式行拼接

  • 圆括号、方括号、花括号内表达式允许被分为多个物理行,无需 使用反斜杠

    • 拼接行可以带有注释
    • 后续行缩进不影响程序结构、允许为空白行
    • 拼接行之间不会有NEWLINE token
  • 三引号"""/'''字符串允许被分为多个物理行

    • 拼接行中不允许带有注释

空白行

空白行:只包含空格符、制表符、进纸符、注释的逻辑行会被忽略, 不生成NEWLINE token

  • 交互式输入语句时,对空白行处理可能因为读取-求值-打印循环 的具体实现而存在差异

    • 标准交互模式解释器中:完全空白逻辑行将会结束一条多行 复合语句

注释

注释:一不包含在字符串内的#开头,在物理行末尾结束

  • 注释标志逻辑行的结束,除非存在隐含行拼接规则
  • 注释在语法分析中被忽略,不属于token

编码声明

编码声明:位于python脚本第一、第二行,匹配正则表达式 coding[=:]\s*([-\w.]+)的注释将被作为编码声明处理

1
# -*- coding: <encoding-name> -*-
  • 表达式第一组指定了源码文件编码
    • 编码声明指定编码名称必须是python所认可的编码
    • 词法分析将使用此编码:语义字符串、注释、标识符
  • 编码声明须独占一行,若在第二行,则第一行也必须为注释
  • 没有编码声明,默认编码为UTF-8
    • 若文件首字节为UTF-8字节顺序标志b\xef\xbb\xbf, 文件编码也声明为UTF-8

缩进

缩进:逻辑行开头的空白(空格符、制表符)被用于计算该行 的缩进等级,决定语句段落组织结构

  • 首个非空白字符之前的空格总数确定该行的缩进层次
    • 缩进不能使用反斜杠进行拼接,首个反斜杠之前空格将确定 缩进层次
  • 制表符被替换为1-8个空白,使得缩进的空格总数为8倍数
    • 源文件若混合使用制表符、空格符缩进,并使得确定缩进 层次需要依赖于制表符对应空格数量设置,将引发 TabError
    • 由于非Unix平台上文本编辑器本身特性,源文件中混合使用 制表符、空格符是不明智的
  • 进纸符
    • 在行首时:在缩进层级计算中被忽略
    • 行首空格内其他位置:效果未定义,可能导致空格计数重置 为0
  • 不同平台可能会显式限制最大缩进层级

INDENT/DEDENT token

  • 读取文件第一行前,向堆栈中压入零值,不再弹出
  • 被压入栈的层级数值从底至顶持续增加
  • 每个逻辑行开头的行缩进层级将和栈顶进行比较
    • 相同:不做处理
    • 新行层级较高:压入栈中,生成INDENT token
    • 新行层级较低:应为栈中层级数值之一
      • 栈中高于该层级所有数值被弹出
      • 每弹出一级数值生成一个DEDENT token
  • 文件末尾,栈中剩余每个大于0数值生成一个DEDENT token

Tokens

型符

  • 空白字符不属于token
    • 除逻辑行开头、字符串内,空格符、制表符、进纸符等 空白符均可分隔token
    • 否则彼此相连的token会被解析为一个不同的token
  • 若存在二义性,将从左至右尽可能长读取合法字符串组成token

Indentifiers

标识符/名称:python标识符语法基于Unicode标准附件UAX-31,有 修改

  • ASCII字符集内可用于标识符与py2一致

    • 大、小写字母
    • 下划线_
    • 数字0-9
  • py3中引入ASCII字符集以外的额外字符

    • 其分类使用包含于unicodedata模块中Unicode字符数据库 版本
  • 标识符没有长度限制、大小写敏感

1
2
3
4
5
identifier   ::=  xid_start xid_continue*
id_start ::= <all characters in general categories Lu, Ll, Lt, Lm, Lo, Nl, the underscore, and characters with the Other_ID_Start property>
id_continue ::= <all characters in id_start, plus characters in the categories Mn, Mc, Nd, Pc and others with the Other_ID_Continue property>
xid_start ::= <all characters in id_start whose NFKC normalization is in "id_start xid_continue*">
xid_continue ::= <all characters in id_continue whose NFKC normalization is in "id_continue*">
  • Lu:大写字母
  • Ll:小写字母
  • Lt:词首大写字母
  • Lm:修饰字母
  • Lo:其他字母
  • Nl:字母数字
  • Mn:非空白标识
  • Mc:含空白标识
  • Nd:十进制数字
  • Pc:连接标点
  • Other_ID_Start:由PropList.txt定义的显式字符列表, 用来支持向后兼容
  • Other_ID_Continue:同上

Keywords

关键字:以下标识符作为语言的保留字、关键字,不能用作普通 标识符

1
2
3
4
5
6
7
False      await      else       import     pass
None break except in raise
True class finally is return
and continue for lambda try
as def from nonlocal while
assert del global not with
async elif if or yield

保留标识符类

以下划线字符开头、结尾的标识符类:具有特殊函数

  • _*:不会被from module import *导入

    • 特殊标识符_:交互式解释器中用于存放最近一次求值 结果,不处于交互模式时无特殊含义、无预定义
  • __*__:系统定义名称

    • 由解释器极其实现(包括标准库)定义
    • 任何不遵循文档指定方式使用__*__行为可能导致无警告 出错
  • __*:类私有名称

    • 在类定义中使用
    • 会以混合形式重写避免基类、派生类私有属性之间出现 名称冲突

字面值

字面值:表示一些内置类型常量

字符串、字节串字面值

1
2
3
4
5
6
7
8
9
10
stringliteral   ::=  [stringprefix](shortstring | longstring)
stringprefix ::= "r" | "u" | "R" | "U" | "f" | "F"
| "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | "Rf" | "RF"
shortstring ::= "'" shortstringitem* "'" | '"' shortstringitem* '"'
longstring ::= "'''" longstringitem* "'''" | '"""' longstringitem* '"""'
shortstringitem ::= shortstringchar | stringescapeseq
longstringitem ::= longstringchar | stringescapeseq
shortstringchar ::= <any source character except "\" or newline or the quote>
longstringchar ::= <any source character except "\">
stringescapeseq ::= "\" <any source character>
1
2
3
4
5
6
7
8
9
bytesliteral   ::=  bytesprefix(shortbytes | longbytes)
bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"
shortbytes ::= "'" shortbytesitem* "'" | '"' shortbytesitem* '"'
longbytes ::= "'''" longbytesitem* "'''" | '"""' longbytesitem* '"""'
shortbytesitem ::= shortbyteschar | bytesescapeseq
longbytesitem ::= longbyteschar | bytesescapeseq
shortbyteschar ::= <any ASCII character except "\" or newline or the quote>
longbyteschar ::= <any ASCII character except "\">
bytesescapeseq ::= "\" <any ASCII character>
  • stringprefixbytesprefix与字面值剩余部分之间不允许 由空白符
  • 源字符集由编码声明定义
  • 字节串字面值只允许ASCII字符(但允许存储不大于256)
  • 两种字面值都可以使用成对(连续三个)单引号、双引号标示 首尾

    • 单引号'':允许包含双引号""
    • 双引号"":允许包含单引号''
    • 三重引号'''"""
      • 原样保留:未经转义的换行、(非三联)引号、空白符
  • 反斜杠\用于对特殊含义字符进行转义

字符串前缀
  • b/B前缀:字节串字面值

    • 创建bytes类型而非str类型实例
    • 只能包含ASCII字符
    • 字节对应数值大于128必须以转义形式表示
  • r/R:原始字符串/字节串

    • 其中反斜杠\被当作其本身字面字符处理
    • 转换序列不在有效
    • 原始字面值不能以单个\结束,会转义之后引号字符
  • f/F:格式化字符串字面值

转义规则
  • 字符串、字节串字面值中转义序列基本类似标准C转义规则

    • \xhh:必须接受2个16进制数码
  • 以下转义序列仅在字符串字面值中可用

    • \N{name}:Unicode数据库中名称为name的字符
    • \uxxxx:必须接受4个16进制数码
    • \Uxxxxxxxx:必须接受8个16进制数码
  • 无法识别的转义序列

    • py3.6之前将原样保留在字符串中
    • py3.6开始,将引发DeprecationWarning,未来可能会 引发SyntaxError
字符串字面值拼接
  • 多个相邻字符串、字符串字面值(空白符分隔),含义等同于 全部拼接为一体

    • 所用引号可以彼此不同(三引号风格也可用)
    • 每部分字符串可以分别加注释
    • 可以包括格式化字符串字面值
  • 此特性是在句法层面定义,在编译时实现

    • 在运行时拼接字符串表达式必须使用+运算符
格式化字符串字面值

格式化字符串字面值:带有f/F前缀的字符串字面值

  • 包含可替换字段,即以{}标示的格式表达式

    • 字符串{}以外部分按字面值处理
    • 双重花括号{ { } }被替换为相应单个花括号
  • 格式表达式被当作正常的包含在圆括号中python表达式处理 ,在运行时从左至右被求值

    • 不允许空表达式
    • lambda空表达式必须显式加上圆括号
    • 可以包含换行:如三引号字符串
    • 不能包含注释
    • 不能\反斜杠,考虑创建临时变量
  • 格式化字符串字面值可以拼接,但是一个替换字段不能拆分到 多个字面值中

  • 格式化字符串不能用作文档字符串,即使其中没有包含表达式

1
2
3
4
5
6
7
8
f_string          ::=  (literal_char | "{{" | "}}" | replacement_field)*
replacement_field ::= "{" f_expression ["!" conversion] [":" format_spec] "}"
f_expression ::= (conditional_expression | "*" or_expr)
("," conditional_expression | "," "*" or_expr)* [","]
| yield_expression
conversion ::= "s" | "r" | "a"
format_spec ::= (literal_char | NULL | replacement_field)*
literal_char ::= <any code point except "{", "}" or NULL>
  • !:标识转换字段

    • !s:对结果调用str()
    • !r:调用repr()
    • !a:调用ascii()
    1
    2
    3
    4
    name = "Fred"
    print(f"he said his name is {name!r}")
    print("he said his name is {repr(name)}")
    # 二者等价
  • ::标识格式说明符,结果使用format()协议格式化

    • 格式说明符被传入表达式或转换结果的.__format__() 方法
    • 省略格式说明符则传入空字符串
    1
    2
    3
    4
    5
    6
    7
    8
    9
    width, precision = 4, 10
    value = decimal.Deciaml("12.345")
    print(f"result: {value: {width}.{precision}}")

    today = datetime(yeat=2017, month=1, day=27)
    print(f"{today: %B %d, %Y}")

    number = 1024
    print(f"{number: #0x}")
  • 顶层格式说明符可以包含嵌套替换字段

    • 嵌套字段可以包含有自身的转换字段、格式说明符,但不能 包含更深层嵌套替换字段

数字字面值

  • 数字字面值不包括正负号
    • 负数实际上是由单目运算符-和字面值组合而成
  • 没有专门复数字面值
    • 复数以一对浮点数表示
    • 取值范围同浮点数
  • 数字字面值可以使用下划线_将数码分组提高可读性
    • 确定数字大小时,字面值之间的下滑线被忽略
    • 下划线可以放在数码之间、基数说明符0x等之后
    • 浮点数中不能直接放在.
整形数字字面值
  • 整形数字字面值没有长度限制,只受限于内存
1
2
3
4
5
6
7
8
9
10
integer      ::=  decinteger | bininteger | octinteger | hexinteger
decinteger ::= nonzerodigit (["_"] digit)* | "0"+ (["_"] "0")*
bininteger ::= "0" ("b" | "B") (["_"] bindigit)+
octinteger ::= "0" ("o" | "O") (["_"] octdigit)+
hexinteger ::= "0" ("x" | "X") (["_"] hexdigit)+
nonzerodigit ::= "1"..."9"
digit ::= "0"..."9"
bindigit ::= "0" | "1"
octdigit ::= "0"..."7"
hexdigit ::= digit | "a"..."f" | "A"..."F"
浮点数字字面值
  • 整形数部分、指数部分解析时总以10为计数
  • 浮点数字面值允许范围依赖于具体实现
1
2
3
4
5
6
floatnumber   ::=  pointfloat | exponentfloat
pointfloat ::= [digitpart] fraction | digitpart "."
exponentfloat ::= (digitpart | pointfloat) exponent
digitpart ::= digit (["_"] digit)*
fraction ::= "." digitpart
exponent ::= ("e" | "E") ["+" | "-"] digitpart
虚数字面值
  • 序数字面值将生成实部为0.0的复数
1
imagnumber ::=  (floatnumber | digitpart) ("j" | "J")

运算符

1
2
3
+       -       *       **      /       //      %      @
<< >> & | ^ ~
< > <= >= == !=

分隔符

1
2
3
4
(       )       [       ]       {       }
, : . ; @ = ->
+= -= *= /= //= %= @=
&= |= ^= >>= <<= **=
  • 以上列表中后半部分为增强赋值操作符
    • 在词法中作为分隔符,同时起运算作用
1
'       "       #       \
  • 以上可打印ASCII字符
    • 作为其他token组成部分时有特殊意义
    • 或对词法分析器有特殊意义
1
$       ?
  • 以上可打印ASCII字符不再Python词法中使用
    • 出现在字符串字面值、注释之外将无条件引发错误

Shell执行控制

符号

命令执行

  • ;:连续执行指令,分割多条命令

    • 所以如果不是在一行内执行,;是可以有任意多个
  • ::内建空指令,返回值为0

  • &&, ||:逻辑与、或,全部(任意)之前的命令执行成功才会 执行下连接中的命令

“转义”

  • \\:转义字符

    • 放在指令前,取消alias
    • 特殊符号前转义,Shell将不对其后字符作特殊处理,当作 普通字符(即$, \', \"
    • 行尾表示连接下一行,回车符只起换行作用,视为空格
  • $:变量符号,表示其后字符串为一个变量

  • \', \":内部视为字符串

  • --:命令行中转义-,否则shell认为-是参数选项

    1
    2
    $ rm -- -file
    # 删除文件`-file`
    • 还可以在之前加上路径避免-被解释为参数选项
    • \''等均无效

引号

单引号''

  • 单引号括起字符都作为普通字符,变量无效

  • 单引号字串中不能出现单独的单引号,使用转义符也不行,但是 可以成对出现,作为字符串拼接使用

双引号""

  • 双引号字串中可以有变量、转义字符

反引号``

反引号扩起字符串表示Shell解释命令,执行时shell首先解释其, 以标准输出替代整个反引号

  • 括号中语句为命令,分号连接

    • ``中的表达式只需要符合C语言的运算规则 即可,甚至可以使用三目预算符、逻辑表达式
  • 命令和括号之间无空格

  • $``可以将命令输出作为变量返回值,同$()

括号

()

  • 命令组/运算表达式:其中的命令列表将在新子shell运行

    • 其中变量之后不能使用,不影响当前shell环境
    • 多个命令之间分号分隔,最后命令可以省略
    • 命令和括号之间可以无空格
  • 命令替换:等同于引号``

    • bash扫描命令行,执行$()结构中命令,将标准输出作为 匿名变量值
    • ()中出现()不需要转义,``需要转义
    • ()中不能使用C风格的运算表达式
    • 部分shell可能不支持(),如:tcsh
  • 初始化数组:参见数组

(())

  • 整数扩展:计算、扩展算数表达式结果

    • 表达式结果为0则退出状态为1、false
    • 表达式结果为1则退出状态为0、true
    1
    2
    a=5;((a++))			# 自增运算符
    b=$((16#5f)) # 进制转换
    • 退出状态和[]完全相反
    • 其中可使用任何符合C语言的运算,包括三目运算符
  • 算术比较:

    • 其中变量可以不使用$前缀、支持多个表达式逗号分隔
    • 可直接使用C风格表达式,如:forwhile循环语句中
1
2
3
4
5
6
7
for((i=0;i<5;i++))
for i in `seq 0 4`
for i iin {0..4}
# 三者等价
if ((i<5))
if [ $i -lt 5 ]
# 二者等价

[][[]]

  • []

    • 条件测试表达式:参见if
    • 数组索引
    • 正则表达式范围
  • [[]]

    • 条件测试表达式:参见if

{}

  • 创建匿名函数

    • 不开启新进程
    • 括号内变量之后可继续使用
    • 括号内命令分号分隔,最后一个语句也要有分号
    • {和第一个语句之间要有空格
  • 字符串

    • 默认值替换:参见字符串默认值替换
    • 获取子串:参见字符串子串
    • 获取切片:参见字符串子串
    • 字符串替换:参见字符串子串
  • $后包括变量名精确分隔变量名,参见变量使用

其他符号

!

Shell中!称为事件提示符,可以方便的引用历史命令:当! 后跟随字母不是空格、换行、回车、=(时,做命令替换

  • ![-]n:引用history中的正数/倒数第n个命令

    • !!:等同!-1,执行上条命令
  • !cmd:引用最近以cmd开头的命令,包括参数

    • !cmd:gs/pattern/replace:将上条cmd开头命令中 pattern替换为replace
  • !?str[?]:引用最近包含str的命令,str可以是参数

  • 参数引用

    • !$:最后一个参数
    • !:-:除最后一个参数
    • !*:所有参数

控制语句

if[]

用于条件控制结构,结构如下

1
2
3
4
if test_expression; then
then command_1
else command_2
fi
  • test <expr>:bash内部命令,判断表达式是否为真

    • 其后只能有一个表达式判断,无法使用逻辑与、或连接
  • [ <expr> ]:基本等同于test

    • 整数比较:-ne-eq-gt-lt
    • 字符串比较:转义形式大、小号\</>
    • 逻辑表达式连接:-o(或)、-a(与)、!(非) (不能使用||(或)、&&(与))
    1
    2
    3
    if [ $? == 0 ]
    if test $? == 0
    # 二者等价
    • 注意内部两边要有空格
    • 事实上是[等同于test]表示关闭条件判断,新版 bash强制要求闭合
  • [[ <expr> ]]条件测试

    • 整数比较:!==<>
    • 字符串:支持模式匹配(此时右侧模式时不能加引号)
    • 逻辑表示式连接:||(或)、&&(与)、!(非)
    1
    2
    3
    4
    if [[ $a != 0 && $b == 1 ]]
    if [ $a -eq 0 ] && [ $b -eq 1]
    if [ $a -eq 0 -a $b -eq 1]
    # 三者等价
    • [[:bash关键字,bash将其视为单独元素并返回退出 状态码

case

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
case chars in
char_pattern_1)
# `)`是必要的
# 匹配即停止,不会下沉
command_1
;;
# 每个模式字符串可以有多条命令,最后一条必须以`;;`结尾
char_pattern_2 | char_pattern_3)
# `|`分隔,或,可以匹配其中一个模式即可
command_2
;;
*)
# 匹配所有字符串模式,捕获所有
command_3
;;
esac
# 返回值位最后执行命令的退出值,未执行命令则为0

while

1
2
3
4
5
6
while test_expression
# test_expression是指`test`、`[]`语句
# 测试条件为真进入循环体
do
command_1
done

until

1
2
3
4
5
until test_exprssion
# 测试条件为假进入循环体
do
command_1
done

for

CStyle

1
2
3
4
5
for ((i=0; i<limit; i++))
# C-style for
do
command_1
done

ListStyle

1
2
3
4
5
for var in var_arr
# list-style for
do
command
done
FileIterator
1
2
3
4
5
6
for var in /path/to/file_regex
# `var`依次取(当前)目录下的与正则表达式匹配的文件名
# 执行循环体语句
do
command
done
  • /path/to/file_regex注意
    • 路径不存在:$var为该字符串
    • 不能用""括起,否则:$var只取路径下所有匹配合并 ,空格分隔
ParamsIterator
1
2
3
4
5
6
for var[ in $*]
# `var`依次取位置参数的值,执行循环体中命令
# `[ in $*]`可以省略
do
command
done
RangeIterator
1
2
3
4
5
6
7
8
9
for i in $(seq start end)
do
command
done

for i in {start..end}
do
command
done

break, continue, exit

  • break[n]:跳出n层循环体,默认跳出一层循环体
  • continue[n]:跳过n层循环体在其之后的语句,回到循环开头 ,默认跳过一次循环体
  • exit:退出程序,后跟返回值

Bash 编程技巧

检查命令是否成功

  • 原版

    1
    2
    3
    4
    5
    6
    7
    echo abcdee | grep -q abcd

    if [ $? -eq 0 ]; then
    echo "found
    else
    echo "not found"
    fi
  • 简洁版

    1
    2
    3
    4
    5
    if echo abcdee | grep -q abc; then
    echo "found"
    else
    echo "not found"
    fi
  • 精简版

    1
    echo abcdee | grep -q abc && echo "found" || echo "not found"

标准输出、错误输出重定向到/dev/null

  • 原版

    1
    $ grep "abc" text.txt 1>/dev/null 2>&1
  • 简洁版

    1
    $ grep "abc" text.txt &> /dev/null

awk使用

  • 原版
    1
    $ sudo xm li | grep vm_name | awk `{print $2}`
  • 简洁版
    1
    $ sudo xm li | awk `/vm_name/{print $2}`

逗号连接所有行

  • 原版:sed

    1
    $ sed ":a;$!N;s/\n/,;ta" test.txt
  • 简洁:paste

    1
    $ paste -sd, /tmp/test.txt

过滤重复行

  • 原版:sort

    1
    $ sort text.txt | unique
  • 简洁版

    1
    $ sort -u text.txt

Bash 脚本执行

脚本执行

#!

脚本首行注释

  • 文件执行时,shell会将文件内容发送至#!之后的解释器上
  • 不限于shell脚本,也适合其他类型的脚本语言
    • 当然要求#为脚本语言支持的注释符
  • 建议在首行使用env命令而不是硬编码解释器路径,这样可以 减少对机器的依赖
    1
    2
    #!/usr/bin/env python
    #!/usr/bin/env shell

4种执行方式

  • $ file_name:表示在当前shell执行文件,需要有文件的执行 权限

  • $ source/. file_namesource.意义一致,表示读取 文件内容在shell中,然后在shell里执行文件内容,需要读权限

  • $ sh file_name:表示开启一个新的shell进程,并读取文件 内容在新的shell中然后执行,同样的需读权限

以下面的文件test.sh为例

1
2
3
4
5
#!/bin/bash
echo "fisrt"
sleep 1000
echo "second"
slepp 1000
  • $ test.sh:产生两个新进程test.sh和sleep,在second输出 之前<ctrl-c>,会同时终止两个进程,不会继续输出second

  • $ sh test.sh:产生两个新进程,shell和sleep,在second 输出之前<ctrl-c>,同样的会同时终止两个进程,不会继续 输出second(实际上first是在新的shell里输出的)

  • source/. test.sh:产生一个新进程sleep,在second输出之前 <ctrl-c>,只有sleep进程被终止,而test.sh的内容在当前 shell里直接执行,当前shell没有被终止,second会继续输出

结论

  • 如果需要对当前shell进行设置,应该使用source/.

  • 否则这三种执行方式除了进程产生、权限要求应该没有差别

Shell环境

环境变量

  • 设置环境变量直接:$ ENV_NAME=value=前后不能有空格) 但是此时环境变量只能在当前shell中使用,需要export命令 导出之后才可在子shell中使用

  • 环境变量设置代理

    1
    2
    export http_proxy=socks://ip
    export https_proxy=socks5://ip

输入输出

  • 0:STDIN_FILENO,标准输入
  • 1:STDOUT_FILENO,标准输出
  • 2:STDERR_FILENO,标准错误

说明:

  • 标准输出和标准错误虽然都是在命令行上显示,但是两个是 不同的流。输出重定向>只能将标准输出重定向,不会将 标准错误重定向,其仍然会在命令行显示

重定向

  • <:重定向标准输入
  • >:标准输出write重定向
  • >>:标准输出add重定向
  • 2>:标准错误重定向

说明:

  • 输出重定向就是1 > outputcommand > output只是省略 1的简写

    • 命名自己不是输出,不能重定向
    • 是命令产生的标准输出重定向
  • 可以通过2>&1将标准错误重定向到标准输出,从而将命令的 标准输出、错误输出同时输出

    • &这里表示等效于标准输出(标准输出的引用)
    • command>a 2>acommand>a 2>&1看起来类似,实际上 前者写法会打开两次a,stderr覆盖stdout,而后者是 引用,不会覆盖、IO效率更高
    • 2>&1放在后面大概是因为需要获取stdout的引用,所以 需要标准输出先给出重定向
    • 这种写法还有个简写&>>&
  • 可以重定向到设备,在*nix系统中,设备也被视为文件

    1
    $ echo "hello" > /dev/tty01

    特别的设备/dev/null可以作为不需要输出的重定向目标

HereDoc Format

HereDoc Format:特殊的重定向,指示shell从标准输入读取输入 直至遇到标记行(前后不能有空白符)

1
2
3
<CMD> << <EOF>
here-doc
<EOF>
  • EOF:标记字符串,常用EOFSTOP
  • 若标记中含有字符被quote(如被引号包括)

    • 结束标记为去除quotation结果
    • here-doc中不执行参数扩展、命令替换、算数扩展
  • 若标记中没有quotation

    • here-doc中执行参数扩展、命令替换、算数扩展
    • 此时\$、反引号需要\转义

管道

|:将一个程序的标准输出发送到另一个程序的标准输入

  • 一些平台会并行启动以管道连接的程序,此时使用类似迭代器 输出、输入能提高效率

Shell内置命令

  • which命令无法找到的命令

set

set:设置所使用的shell选项、列出shell变量

  • :不带参数,显示全部shell变量
  • -a:输出之后所有至export(环境变量)
  • -b:使被终止后台程序立即汇报执行状态
  • -B:执行括号扩展
  • -C:重定向所产生的文件无法覆盖已存在文件
  • -d:shell默认使用hash表记忆已使用过的命令以加速 执行,此设置取消该行为
  • -e:若指令回传值不为0,立即退出shell
  • -f:取消使用通配符
  • -h:寻找命令时记录其位置???
  • -H:(默认)允许使用!<编号>方式执行history中 记录的命令
  • -k:命令=被视为设置命令的环境变量
  • -m:监视器模式,启动任务控制
    • 后台进程已单独进程组运行
    • 每次完成任务时显示包含退出的状态行
  • -n:读取命令但不执行
    • 通常用于检查脚本句法错误
  • -p:允许set-user/group-id
    • 禁止处理$ENV文件、从文件中继承shell函数
  • -P:处理cd等改变当前目录的命令时,不解析符号链接
  • -t:读取、执行下条命令后退出
  • -u:使用未设置变量作为错误处理
  • -v:输入行被读取时,显示shell输出行
  • -x:显示简单命令的PS4扩展值(包括所有参数)、当前命令 的环境变量
  • -o:option-name,下列之一
    • allexport:同-a
    • braceexpand shell:(默认)执行花括号扩展
    • emacs:(默认)使用emacs风格命令行编辑接口
    • errexit:同-e
    • errtrace:同-E
    • functrace:同-T
    • hashall:同-h
    • histexpand:同-H
    • history:记录命令历史
    • ignoreeof:读取EOF时不退出shell
    • interactive-comments:允许交互式命令中出现注释
    • keyword:同-k
    • monitor:同-m
    • noclobber:同-C
    • noexec:同-n
    • noglob:同-f
    • noglob:currently accepted but ignored
    • nohash:同-d
    • notify:同-b
    • nounset:同-u
    • physical:同-P
    • pipfail:管道命令返回值为最后返回值非0命令的状态, 若没有非0返回值返回0
    • posix:改变shell属性以匹配标准,默认操作不同于 POSIX1003.2标准
    • priviledged:同-p
    • verbose:同-v
    • vi:使用vi风格的命令编辑接口
    • xtrace:同-x
  • +:加以上参数取消标志位设置(包括o参数)
  • --:给所有剩余参数设置标志位,没有剩余参数则unset
  • -:给所有剩余参数设置标志位
  • $-中存放有当前已设置标志位

let

let:执行计算的工具,用于执行一个、多个表达式

  • 变量计算中不需要$标识变量
  • 表达式中包含特殊字符,需要引起来

declare

declare:声明变量内容

  • -a:声明变量为普通数组
  • -A:声明变量为关联数组(下标支持字符串,类似字典)
  • -i:声明变量为整形
  • -r:声明变量只读
  • -x:设置为环境变量(export
  • -g:在函数中创建全局变量
  • +:和以上联合使用,取消定义的变量类型

  • -f:列出脚本中定义的函数名称、函数体

  • -F:列出脚本中定义的函数名称
  • -p:查看变量属性、值

read

read:从标准输入读入变量内容

1
2
$ read [<option>] <var>[ <var2>...]
$ read -p "Enter names: " name1, nem
  • 读取值数目大于变量数目时,多余值均赋给最后变量
  • -p:命令行提示内容
  • -n:不换行
  • -d:分隔标记
  • -t:阻塞等待时常,之后返回非零
  • -s:隐藏输入
  • -r:反折号不被视为转义标记
1
2
3
cat README | while read -r line; do
echo $line
done

shift

shift:移除参数列表中头部部分参数,缺省移除1个

  • shift移除从$1开始,无法移除$0

getopts

getopts:逐个读取解析单字符指示的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function func (){
echo OPTIND: $OPTIND
while getopts ":a:B:cdef" opt; do
case $opt in
a) echo "this is -a the arg is ! $OPTARG at $OPTIND" ;;
B) echo "this is -B the arg is ! $OPTARG at $OPTIND" ;;
c) echo "this is -c the arg is ! $OPTARG at $OPTIND" ;;
\?) echo "Invalid option: -$OPTARG" ;;
esac
done
echo OPTIND: $OPTIND
echo $@
shift $(($OPTIND - 1))
echo $@

}
func -a 23 -B 1904-03-04 343 age
  • $OPTARG:参数值
  • $OPTIND:在参数列表中位移,初始值为1,常配合shift 使用剔除已处理参数
  • 遇到未指定option则返回0
  • option字符后::字符可以带有参数,赋给$OPTARG;否则 仅表示标志,仅该字符被处理

  • option_string开头:可以避免错误输出

    • :标记option不带参数时
      • 待匹配值设为:
      • $OPTARG设为option
    • option无效时
      • 待匹配值设为?
      • $OPTARG设为option
  • 函数内部处理函数参数,否则处理脚本参数
  • 参数标识-可省略

Linux介绍

Linux版本

内核版本

内核版本号由3个数字组成X.Y.Z-P

  • X:主版本号,比较稳定,短时间不会改变
  • Y:次版本号,表示版本类型
    • 偶数:稳定版
    • 奇数:测试版
  • Z:发布号,数字越大,功能越完善
  • P:patch号

Linux分区

/boot引导分区目录

该分区(目录)存放系统内核、驱动模块引导程序,需要独立 分区

  • 避免(根)文件系统损坏造成无法启动
  • 避使用lilo引导时1024柱面问题(Grub无此问题)
  • 方便管理多系统引导

/boot修复

进入grub模式后#todo

/swap分区目录

系统物理内存不足时,释放部分空间,其中数据被临时保存在 swap空间中

  • 不是所有物理内存中交换的数据都会被放在交换空间中,有部分 数据直接交换到文件系统

  • 交换空间比内存慢

  • 安装时,系统会尝试将交换分区安装到磁盘外端

  • 有多个磁盘控制器时,在每个磁盘上都建立交换空间

  • 尽量将交换空间安装在访问在频繁的数据区附近

  • 交换空间大小一般设置为内存1-2倍

  • 不推荐为交换空间划分单独分区,可以使用交换文件作为交换 空间,方便、容易扩展
交换文件
1
2
3
4
5
6
7
8
9
10
11
12
13
$ dd if=/dev/zero of=/swapfile bs=1024 count=32000
#
$ fallocate -l 32G /swapfile
# 创建有连续空间的交换文件,大小为1024*32000=32G
$ chmod 600 /swapfile
# 修改交换文件权限
$ mkswap /swapfile
# 设置交换文件

$ /usr/sbin/swapon /swapfile
# 激活上步创建的`/swapfile`交换文件
$ /usr/sbin/swapoff swapfile
# 关闭交换文件
  • 不需要交换文件时可以直接rm删除
  • 可以在fstab文件中添加交换文件,自动挂载,格式参见 config_files

/根分区目录

  • /usr:用户程序
  • /sbin:系统管理员执行程序
  • /bin:基本命令
  • /lib:基本共享库、核心模块
  • /home:用户目录
  • /etc:配置文件目录
  • /opt:附加应用程序包目录
  • /mnt:设备/文件系统挂载目录
  • /dev:设备
  • /tmp:临时文件
  • /var:可变信息区
    • file spool
    • logs
    • requests
    • mail
  • /proc:进程(映射)信息

Terminal、CLI、Shell、TTY

Terminal

  • Termianl 终端:计算机领域的终端是指用于 与计算机进行交互的输入输出设备,本身不提供运算处理功能

    • 大部分情况下,终端将用户的字符以外键盘输入转为控制序列
    • 但接收到 <C-C> 等特殊组合键时,发送特殊信号
  • Console 控制台:和计算机一体的特殊终端,用于管理主机,比普通终端权限更高

    • 一台主机一般只有一个控制台,但可以连接多个普通终端
    • Console、Terminal随着PC普及已经基本时同义词

TTY

  • TTY:原含义即为直电传打字机 TeletypePrinterTeletypeWriter:键盘输入指令、纸带打印信号

    • UNIX 为支持电传打字机设计了名为 tty 的子系统
    • 之后 tty 名称被保留成为终端的统称(虽然终端设备不局限于 tty
  • UNIX 系统中

    • 具体终端硬件设备抽象为操作系统内部 /dev/tty* 设备文件
    • /dev/tty[1-6] 即对应 6 个虚拟控制台
  • 另外,早期计算机上 Serial Port 最大用途就是连接终端设备

    • 所以会把行端口上设备同样抽象为 tty 设备
    • /dev/ttyS* 对应串口设备
  • Linux TTY/PTS概述
  • Linux 系统中,<C-A—[F1-F6]> 可以切换终端
  • 可通过 $ stty -a 查看当前终端设置

分类

  • Character/Text Terminal:字符终端,只能接受、显示文本信息的终端

    • Dumb Terminal:哑终端
    • Intelligent Terminal:智能终端,相较于哑终端
      • 理解转义序列
      • 定位光标、显示位置
  • Graphical Terminal:图形终端,可以显示图形、图像

    • 现在专门图形终端已经少见,基本被 全功能显示器 取代

Terminal Emulator

终端模拟器:默认传统终端行为的程序,用于与传统的、不兼容图形接口命令行程序(如:GNU 工具集)交互

  • CLI 程序,终端模拟器假装为传统终端设备
  • 对现代图形接口,终端模拟器假装为 GUI 程序
    • 捕获键盘输入
    • 将输入发送给 CLI 程序(bash
    • 得到命令行程序输出结果
    • 调用图形接口(如:X11),将输出结果渲染至显示器
  • tty[1-6] 也是终端模拟器,只是不运行在图形界面中、由内核直接提供,也称虚拟控制台

ShellTerminal

  • Shell 更多指提供和内核交互入口的软件,提供

    • 命令提示符 Prompt
    • 行编辑、输入历史、自动补全(但是也有些终端自己实现 此功能)
  • Terminal 更多指 IO 端口硬件,提供

    • 上、下翻页查看内容
    • 终端中复制、粘贴功能

Shell

pc_architecture

Shell:提供 用户界面 的程序,接受用户输入命令和内核沟通

  • Shell 向用户提供操作系统入口

    • 避免普通用户随意操作导致系统崩溃
    • 虽然Shell会调用其他应用程序,其他应用程序再调用系统调用,而不是直接与内核交互
  • Command-Line Interface:命令行 Shell,通常不支持鼠标,通过键盘输入指令

    • shBourne Shell
    • bashBourne-Again Shell
    • zhsZ Shell
    • fishFriendly Interactive Shell
    • cmd.exe:这个应该看作是 Shell,而不是 Terminal
      • 可与内核进行交互
      • 接受键盘输入是其宿主的功能(即宿主作为隐式 Terminal Emulator
    • PowerShell
  • GUIGraphic User Interface 图形 Shell

    • Windows 下的 explorer.exe