星空璀璨

使用alternatives工具进行版本控制

个人感觉alternatives挺不好用的,真要进行版本管理还有很多方法(

alternatives大致原理

关于alternatives是什么的已经有很多教程,大致是一个进行版本管理的应用,比如系统中装了两个版本以上的java,这个时候可以用alternatives进行java版本的切换。

其本质是用了Linux中链接的机制,分成linknamepath

  1. link是应用查找的位置,比如/usr/bin这种大多数系统shell默认的应用查找位置,比如/usr/bin/java就是java程序的查找位置。
  2. name充当linkpath的中介,同时也是alternatives进行版本控制的关键。
  3. path是应用真实存放的位置,比如jdk11的java存放于/usr/lib/jvm/jdk-1.11.1-openjdk-amd64/bin/java,jdk17的java存放于/usr/lib/jvm/jdk-1.17.9-openjdk-amd64/bin/java,这种情况下就需要进行版本控制。

以上述为例,alternatives会如此处理链接:

/usr/bin/java -> /etc/alternatives/java -> /usr/lib/jvm/jdk-1.11.1-openjdk-amd64/bin/java

由于查找目录在/usr/bin下,因此用户运行的java最终会是jdk11版本,如果要切换到17,只需将最终的链接切换至/usr/lib/jvm/jdk-1.17.9-openjdk-amd64/bin/java即可。

使用

alternatives对应的命令是update-alternatives,常用的指令如下:

  • update-alternatives --install <link> <name> <path> <priority> [--slave <link> <name> <path> <priority> ...] 为应用注册一个链接,通过这个之后可以通过--config <name>进行选择,--slave格式与install类似,在install后面的链接被选择后会跟着一起更改,对于应用版本的完全切换非常有用。
  • update-alternatives --config <name> 切换应用版本,会列出已经使用install注册后的链接进行选择。

更方便的alternatives切换应用版本

由于不能批量指定,因此alternatives还是比较麻烦的,这里对于一些常见的应用其实alternatives已经提供了一些脚本进行更方便的切换,这里以阿里巴巴的dragonwell为例(阿里巴巴的jvm实现),对于java版本控制,alternatives提供了update-java-alternatives应用,本质上是一个脚本,存放于/usr/sbin目录,其脚本内容如下:

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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/bin/bash

shopt -s dotglob

prog=$(basename $0)

usage()
{
rv=$1
cat >&2 <<-EOF
usage: $prog [--jre-headless] [--jre] [--plugin] [-v|--verbose]
-l|--list [<jname>]
-s|--set <jname>
-a|--auto
-h|-?|--help
EOF
exit $rv
}

action=
uaopts='--quiet'

while [ "$#" -gt 0 ]; do
case "$1" in
-a|--auto)
[ -z "$action" ] || usage 1
action=auto;;
-hl|--jre-headless)
hlonly=yes;;
-j|--jre)
jreonly=yes;;
--plugin)
pluginonly=yes;;
-l|--list)
[ -z "$action" ] || usage 1
action=list
if [ "$#" -gt 0 ]; then
shift
jname=$1
fi
;;
-s|--set)
[ -z "$action" ] || usage 1
action=set
shift
[ "$#" -gt 0 ] || usage 1
jname=$1
;;
-v|--verbose)
verbose=yes
uaopts="${uaopts/--quiet/}";;
-h|-?|--help)
usage 0;;
-*)
echo "X: $1"
usage 1;;
*)
break;;
esac
shift
done

[ "$#" -eq 0 ] || usage 1
[ -n "$action" ] || usage 1

which='^(hl|jre|jdk|jdkhl|plugin|DUMMY) '
if [ -n "$hlonly$jreonly$pluginonly" ]; then
which='^('
[ -n "$hlonly" ] && which="${which}hl|"
[ -n "$jreonly" ] && [ -n "$hlonly" ] && which="${which}jre|"
[ -n "$jreonly" ] && [ -z "$hlonly" ] && which="${which}hl|jre|"
[ -n "$pluginonly" ] && which="${which}plugin|"
which="${which}DUMMY) "
fi

top=/usr/lib/jvm

if [ -n "$jname" ]; then
arch=$(dpkg --print-architecture)
if [ ! -x $top/$jname/bin/java ] && [ -x $top/$jname-$arch/bin/java ]; then
echo >&2 "$prog: obsolete <jname>, please use $jname-$arch instead"
jname=$jname-$arch
fi
case "$jname" in
/*) jdir=$jname; jname=$(basename $jdir);;
*) jdir=$top/$jname
esac
if [ ! -d $jdir ]; then
echo >&2 "$prog: directory does not exist: $jdir"
exit 1
fi
if [ -f $top/.$jname.jinfo ]; then
jinfo=$top/.$jname.jinfo
elif [ -f $top/$jname.jinfo ]; then
jinfo=$top/$jname.jinfo
else
echo >&2 "$prog: file does not exist: $top/.$jname.jinfo"
exit 1
fi
fi

vecho()
{
[ -z "$verbose" ] || echo >&2 "$@"
}

jinfo_files=

do_auto()
{
vecho "resetting java alternatives"
awk "/$which/ {print \$2}" $top/*.jinfo | sort -u \
| \
while read name; do
update-alternatives $uaopts --auto $name
done
}

do_list()
{
vecho "listing java alternatives:"
for i in ${jinfo:-$top/*.jinfo}; do
alias=$(basename ${i%.jinfo})
alias=${alias#.}
prio=$(awk -F= '/priority=/ {print $2}' $i)
printf "%-30s %-10s %s\n" $alias "$prio " $top/$alias
[ -n "$verbose" ] && egrep "$which" $i
done
}

do_set()
{
do_auto

awk "/$which/ {print}" $jinfo | sort -u \
| \
while read type name location; do
if [ $type = jdk -a -z "$hlonly$jreonly$pluginonly" -a ! -f $location ]; then
echo >&2 "$prog: jdk alternative does not exist: $location"
continue
fi
if [ $type = plugin -a -z "$hlonly$jreonly" -a ! -f $location ]; then
echo >&2 "$prog: plugin alternative does not exist: $location"
continue
fi
update-alternatives $uaopts --set $name $location
done
}

if [ "$action" != list ] && [ "$(id -u)" -ne 0 ]; then
echo >&2 "$prog: no root privileges"
exit 1
fi

do_$action

分析该脚本,可以看到其本质是调用了update-alternatives进行批量的应用版本切换(do_set函数),其中会读取top变量所指定的目录下的.*.jinfo文件进行配置,这个文件配置大致如下(以我系统上安装的jdk11为例):

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
name=java-11-openjdk-amd64
alias=java-1.11.0-openjdk-amd64
priority=1111
section=main

hl java /usr/lib/jvm/java-11-openjdk-amd64/bin/java
hl jjs /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs
hl keytool /usr/lib/jvm/java-11-openjdk-amd64/bin/keytool
hl rmid /usr/lib/jvm/java-11-openjdk-amd64/bin/rmid
hl rmiregistry /usr/lib/jvm/java-11-openjdk-amd64/bin/rmiregistry
hl pack200 /usr/lib/jvm/java-11-openjdk-amd64/bin/pack200
hl unpack200 /usr/lib/jvm/java-11-openjdk-amd64/bin/unpack200
hl jexec /usr/lib/jvm/java-11-openjdk-amd64/lib/jexec
jdkhl jar /usr/lib/jvm/java-11-openjdk-amd64/bin/jar
jdkhl jarsigner /usr/lib/jvm/java-11-openjdk-amd64/bin/jarsigner
jdkhl javac /usr/lib/jvm/java-11-openjdk-amd64/bin/javac
jdkhl javadoc /usr/lib/jvm/java-11-openjdk-amd64/bin/javadoc
jdkhl javap /usr/lib/jvm/java-11-openjdk-amd64/bin/javap
jdkhl jcmd /usr/lib/jvm/java-11-openjdk-amd64/bin/jcmd
jdkhl jdb /usr/lib/jvm/java-11-openjdk-amd64/bin/jdb
jdkhl jdeprscan /usr/lib/jvm/java-11-openjdk-amd64/bin/jdeprscan
jdkhl jdeps /usr/lib/jvm/java-11-openjdk-amd64/bin/jdeps
jdkhl jfr /usr/lib/jvm/java-11-openjdk-amd64/bin/jfr
jdkhl jimage /usr/lib/jvm/java-11-openjdk-amd64/bin/jimage
jdkhl jinfo /usr/lib/jvm/java-11-openjdk-amd64/bin/jinfo
jdkhl jlink /usr/lib/jvm/java-11-openjdk-amd64/bin/jlink
jdkhl jmap /usr/lib/jvm/java-11-openjdk-amd64/bin/jmap
jdkhl jmod /usr/lib/jvm/java-11-openjdk-amd64/bin/jmod
jdkhl jps /usr/lib/jvm/java-11-openjdk-amd64/bin/jps
jdkhl jrunscript /usr/lib/jvm/java-11-openjdk-amd64/bin/jrunscript
jdkhl jshell /usr/lib/jvm/java-11-openjdk-amd64/bin/jshell
jdkhl jstack /usr/lib/jvm/java-11-openjdk-amd64/bin/jstack
jdkhl jstat /usr/lib/jvm/java-11-openjdk-amd64/bin/jstat
jdkhl jstatd /usr/lib/jvm/java-11-openjdk-amd64/bin/jstatd
jdkhl rmic /usr/lib/jvm/java-11-openjdk-amd64/bin/rmic
jdkhl serialver /usr/lib/jvm/java-11-openjdk-amd64/bin/serialver
jdkhl jaotc /usr/lib/jvm/java-11-openjdk-amd64/bin/jaotc
jdkhl jhsdb /usr/lib/jvm/java-11-openjdk-amd64/bin/jhsdb
jdk jconsole /usr/lib/jvm/java-11-openjdk-amd64/bin/jconsole

因此我们可以借用这个脚本和配置文件将我们自己手动安装的软件进行alternatives一键配置。

首先设置在/usr/lib/jvm/目录下的链接,链接至需要部署的软件的目录:

1
royenheart@VM-4-16-debian:~$ ln -s /home/royenheart/.local/dragonwell-17.0.3.0.3+7-GA/ /usr/lib/jvm/dragonwell-17

然后修改配置文件存放于/usr/lib/jvm/目录下,可通过sed批量替换

1
sed -i 's/java-11-openjdk-amd64/dragonwell-17/g' .xxx.jinfo

最后直接通过/usr/sbin/update-java-alternatives --set dragonwell-17进行一键切换,set后的名称为.jinfo文件里name的设置。

总结

如果只涉及到包管理安装(会自动注册alternatives和生成对应的配置文件),那么alternatives也是比较轻量方便的版本控制做法,但如果涉及到自己安装的软件(很多时候是直接二进制文件解压进行安装),又不太想破坏环境变量,alternatives显得有点鸡肋。

计算机对数的计算

个人计算机组成原理学习记录

各种数的表示方法

  1. 原码(机器码),以此表示的数最高位不代表数值而是符号,运算时符号位和数值位分开运算
  2. 反码,负数时原码除符号位外取反,正数不变,运算时(+/-)符号位和数值位可一起进行运算,但会产生-0和+0
  3. 补码,负数时原码除符号位外取反+1,正数不变,运算时(+/-)符号位和数值位可一起进行运算,符号位即可表示符号又可以当作数值位进行运算,表示范围多一个(4位可表示-8~7)
  4. 移码/增码,补码最高位取反,最高位1表示正数,0表示负数。这样做可以使移码和原码(真值)在$-2^{n-1}$ ~ $2^{n-1}-1$区间呈线性正比关系,本质上是补码+偏置值,对于8位补码,偏置值为$2^{7}$。另一种移码和真值在$-2^{n-1}+1$ ~ $2^{n-1}-1$区间呈线性正比关系,偏置值是$2^{n-1} - 1$,这样的好处是留出指数$-2^{n-1}$(指数全为1)和$-2^{n-1}+1$(指数全为0)用作其他用途(特殊值)。
  5. 规格化浮点数,类似科学计数法:$+/-1.xxxxx_2 * 2^{E}$,1隐含,不用写在尾数位。

浮点数规格化表示特殊值(对于计算异常等更方便)

  1. 表示0:指数为0(负指数超出最小允许值);尾数为0;符号位0为+0,1为-0
  2. 表示无穷:指数为1(正指数超出最大允许值);尾数为0;符号位0为正无穷,1为负无穷。
  3. 表示非数(NaN):指数为1;尾数非0;符号位0/1

除法

除法最重要的是比较(绝对值)的步骤,要以比较的结果来判断商取0还是1。

对于X,Y的绝对值比较,可以通过|x|和|y|取绝对值后比较,也可以通过x+y(异号)=r/x-y(同号)=r的方法比较,当异号时r与y同号表示y的绝对值大,当同号时r与y同号表示y绝对值小。

并且注意,由于补码运算得到的商相当于以反码进行运算,因此x,y异号,商为负数,若够减时上商1会导致原码不正确,因此x,y异号够减时上商0。

补码运算最后的余数是以补码表示的。

在补码运算中,其绝对值比较就可以有下述的关系:

补码运算绝对值关系
[x]_补与[y]_补 比较操作
余数[r]_补与除数[y]_补 操作
同号 [x]_补+[-y]_补 同号,表示够减,或者说y绝对值大 1 当作[x]_补,左移+[-y]_补
异号,不够减 0 不恢复余数法左移+[y]_补
异号 [x]_补+[y]_补 同号,不够减 1 不恢复余数法左移+[-y]_补
异号,够减 0 当作[x]_补,左移+[y]_补

实际运算中商的精度一般与x,y精度相同,余数最后乘上$2^{-n}$,n为左移次数

商的校正

前面商的取值实际上是按照反码的方式进行的,当商最后得出为负,则会因反码与补码之间末位1的区别导致误差,因此有下列两种方式解决:

  1. 末位恒置1法

最后的商末位固定为1,即运算至最后的位数时,此时余数左移,商末位固定为1,除法结束

  1. 校正法

即运算至最后的位数时,仍按表格进行正常操作得到余数和商,之后商若为负,则加$2^{-n}$矫正,n为左移的次数,余数若和除数补码呈不够减的关系,则需要恢复余数,对于x、y同号,则加上[y]_补,若x、y异号,加上[-y]_补

浮点数运算

运算概念

  1. 舍入,类似十进制计算的四舍五入
  2. 对阶,使两数阶码相等以方便运算
  3. 规格化,使浮点数符合科学计数法($(1.xxx)_2 * 2^{E-127}$)

浮点数计算实质

规格化浮点数:

$A=M_a \cdot 2^{E_a}$ 和 $B=M_b \cdot 2^{E_b}$

  1. $A \pm B = (M_a \pm M_b \cdot 2^{-(E_a-E_b)}) \cdot 2^{E_a}$
  2. $A * B = (M_a * M_b) \cdot 2^{E_a + E_b}$
  3. $A / B = (M_a / M_b) \cdot 2^{E_a - E_b}$

浮点数运算可能结果

  1. 阶码上溢:无穷。
  2. 阶码下溢:0。
  3. 尾数溢出:尾数最高有效位进位,则右规将进位加入,指数增加。此时计算的尾数(补码表示)连同符号位右移,将移出的位放入附加位作为
  4. 非规格化尾数:数值部分高位0,左规,指数减少。浮点数运算时加上隐含的1,若运算后高位为0,就进行左规。左规尾数左移,附加位移出对应位数至尾数
  5. 右规、对阶有效位缺失:类似四舍五入,有效位优先,进行尾数舍入。参考舍入规则

上溢和下溢也是为什么指数使用移码且偏置常量为$2^{n-1} - 1$的原因。

附加位

为提高浮点数精度,IEEE754规定附加位(中间结果右边加2个附加位):

  1. Guard(保护位):significand(mantissa,尾数)右边的位
  2. Round(舍入位):保护位右边的位
  3. Stick(粘连位):舍入位右边有任何非0数,粘连位为1,否则0。

作用:

  1. 保护对阶右移、运算中间结果。
  2. 左规使移到尾数。
  3. 舍入依据。

舍入

用于计算最后进行舍入

IEEE 754规定的浮点数右规只需要1次。

舍入规则(看附加位):

  • 01:舍
  • 11:入
  • 10:强迫结果偶数
  1. 就近舍入(0舍1入法)
  2. 朝正无穷舍入(离待舍入尾数最近的数)
  3. 朝负无穷舍入
  4. 朝0方向舍入:直接截去

溢出时判断和处理(尾数补码表示,看符号位)

  1. 单符号位:Cf最高数值位进位,Cs符号位进位。相同时结果正确,不同时溢出。
  2. 双符号位:第一符号位$S_{f1}$和第二符号位$S_{f2}$不相同溢出。最高符号位$S_{f1}$代表真正的符号。

使用Perf工具分析程序性能

仅个人学习与记录

perf

perf是Linux内核提供的一个性能分析工具,可以跟踪程序的运行并分析其各种性能比如CPU负载、内存占用等

安装/开启perf

  1. debian
1
2
sudo apt install linux-perf
sudo apt install linux-perf-$(uname -r)
  1. ubuntu
1
sudo apt install linux-tools-$(uname -r) linux-cloud-tools-$(uname -r)
  1. CentOS/openEuler
1
sudo yum install perf

使用flamegraph输出热点图

flamegraph地址

下载安装后可配合perf输出的数据生成程序直观的热点函数图进行进一步的分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
benchmark() {
fileName=$1
outputName=$2
perf record -e cpu-clock -g -o ${fileName}.data ./${fileName}
perf script -i ./${fileName}.data &> ./${fileName}.unfold
stackcollapse-perf.pl ./${fileName}.unfold &> ./${fileName}.folded
flamegraph.pl ./${fileName}.folded > ./benchmarks/${fileName}.svg
mv ${fileName}.data ${fileName}.unfold ${fileName}.folded ./data
}

files=("matrix_no_optimize" "matrix_o1" "matrix_o2" "matrix_o3" "matrix_of")

for file in ${files[@]}
do
benchmark ${file} ${file}
done

一些使用问题

  1. Accesss to performance monitoring and observability operations is limited

解决方法:

1
sudo sysctl -w kernel.perf_event_paranoid=-1

常用命令

perf stat ls - 打印出程序使用硬件的情况

参考资料

使用EnvironmentModule管理linux环境

在linux下环境设置是一个很重要的配置环节,特别是在多用户的情况下

先上官方教程

Environment Module

简化shell初始化的工具。在设置环境的时候,
我们一般使用脚本批量设置或者主动在shell配置环境内设置环境

Environment Module 使用modulefile文件进行环境的管理,相当于把环境设置模块化,
这样我们在进行不同用户,不同节点的环境设置时可以分别引入不同的模块管理,
简化工作。

安装

官网下载源代码进行编译安装

下载得到源代码modules-xxx

解压进行安装

1
2
3
4
5
6
7
sudo apt install -y autoconf tclsh tcl-dev tk-dev mesa-common-dev libjpeg-dev libtogl-dev
tar -xvf modules-xxx

cd modules-xxx
./configure
make
make install

CentOS使用包管理器安装

1
sudo yum install -y environment-modules

完全编译安装

当没有root权限且没有被赋予权限使用包管理器的情况下,若缺少Environment Modules的依赖(往往是tcl依赖),这个时候可以通过同时编译安装tcl解决Environment Modules编译问题:

tcl依赖下载地址

  1. 首先解压tcl依赖源码包,进入解压后目录中的unix目录,使用configure脚本进行编译配置。
  2. 此时不对tcl进行进一步的编译,而是切换到Environment Modules的源码目录,使用./configure --with-tcl=/path/to/tcl/build命令进行编译配置,/path/to/tcl/build为刚刚进行tcl源码编译配置的目录,此参数用于指定tclConfig.sh文件的位置以便modules找到tcl依赖。
  3. 接下来进行正常的编译安装即可。

设置环境变量

Environt-Module为多个Shell解释器提供了环境变量设置脚本,需要使用这些脚本初始化软件的环境变量

tips:若是包管理器安装的,环境配置文件在/usr/share/Modules下

source /InstallFolder/modules-xxx/init/bash

可以添加到bashrc

1
2
echo "source /path/to/modules-xxx/init/bash" >> ~/.bashrc
source ~/.bashrc

为bash设置module,也可以为其他shell设置,
init里面提供了针对多种shell设置其应用环境变量的脚本

之后可执行module命令进行环境变量的维护。

设置模块

$ module avail

列出当前可用模块

$ module load use.own

加载自带模块use.own,加载后会在用户家目录建立privatemodules目录,
之后可在此目录下添加自定义的模块配置文件

$ module list

列出当前已经加载的模块

$ module load

加载指定模块

$ module unload

卸载指定模块

$ module help

列出帮助

$ module use < folder >

增加模块查找的目录,使用module avail将列出增加的目录下可用的模块,不使用时使用命令module unuse < folder >即可。

自定义模块

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
#%Module -*- tcl -*-

# 显示 module help 主要内容
## 设置之后可以使用 module help xxx 列出此模块的帮助内容
proc ModulesHelp { } {
puts stderr "main contents"
}

# 显示 module whatis 主要内容
## 设置之后可以使用 module whatis xxx 列出此模块的信息
module-whatis "main contents"

# module 此模块加载前需要加载的模块类,加载失败会报错
prereq xxx

# module 声明与此模块冲突的模块,也可以是存放冲突模块的文件名
conflict xxx

# 加载此模块的同时加载其他模块
module load xxx

# 设置环境变量(设置为xxx)
setenv something xxx

# 添加环境变量(添加xxx)

append-path PATH xxx

MODULEPATH

此环境变量用于设置module查找模块的路径,若通过包管理器默认安装,可于/usr/share/modules/init/bash文件中添加:

1
export MODULEPATH=xxx:xxx

该语句设置后source该文件可重新设置module查找模块路径

1
2
3
4
5
6
7
## 使用envrionment module运行环境变量设置脚本配置环境

module实质为tcl脚本文件,无法运行shell命令

因此无法通过`source xxx.sh`脚本的方式添加环境变量

可以先获取xxx.sh内定义的环境变量,再加到我们的模块文件中

资料引用

Docker配置JupyterNoteBook服务器

设计思路

使用vps搭建jupyterNotebook服务器,设置域名和端口映射,已经映射容器内部目录与服务器目录

  • 配置域名解析至服务器的公网ip,这样我们可以通过域名+端口的方式连接至jupyterNotebook
  • 设置端口映射,在运行构建好jupyter环境的docker容器时将其开启的端口与vps端口映射,以便访问
  • 设置容器内部文件夹与服务器文件夹的映射,使得容器意外终止后内部数据不会被删除

设计流程

安装docker->下载docker镜像->创建容器并配置相关环境->制成镜像并运行->配置网络并在浏览器中访问

或者使用dockerfile自动构建

安装docker

具体安装细节请参考官方文档

也可移步至本人的另一文档

下载docker镜像

本人采用ubuntu系统作为运行jupyternootbook的系统

1
$ docker pull ubuntu:latest

创建容器并配置相关环境

docker run -it --name djs ubuntu:latest

$ cd && wget

制成镜像并运行

首先更新系统apt update然后下载必要的软件apt install wget vim
若使用dockerfile进行自动构建,可不下载vim

下载anaconda官网提供的shell脚本安装conda环境

运行shell脚本安装conda(使用/bin/bash),当安装完毕后执行conda init bash并重启终端(exit),
执行conda create –name DJS && conda activate DJS配置环境

通过conda环境安装jupyter:conda install -c conda-forge jupyter-lab

生成jupyter-notebook的启动参数jupyter-notebook --generate-config

修改~/.jupyter/jupyter_notebook_config.py文件并添加以下参数:

  1. c.NotebookApp.ip = ‘‘ - 配置允许远程访问的ip地址,表示任何地址均有权限。可自行修改成想要开放的ip地址
  2. c.NotebookApp.notebook_dir = dir_name - 配置jupyter-notebook的工作目录,在此目录下修改、添加程序文件
  3. c.NotebookApp.token = ‘’ - 配置访问的token,也可以设置访问的密码

创建dir_name目录,作为jupyter-notebook的工作目录

至此容器环境设置完毕,之后可通过docker build命令加上对应参数从容器生成镜像

配置网络并在浏览器中访问

假设生成的镜像名字是djs:v1,我们可以通过
docker run -dit --name containerName -p 7777:8888 -v /hostWorkDir:/dir_name djs:v1 jupyter-notebook
后台运行docker容器,同时开启jupyter-notebook服务。
此命令将容器的8888端口(jupyter-notebook开启的默认端口)与宿主机的7777端口进行映射,
同时将宿主机的hostWorkDir目录挂载至容器中jupyter-notebook服务的工作目录,做到数据不在容器中存储。

要在浏览器中访问,我们需要能通过ip、域名访问到服务器并开启7777端口

可以通过http://localhost:7777本地访问

若要设置ssl证书通过https协议进行访问,需要提供证书并修改相关参数

不推荐使用root账户运行服务,建议开一个新的普通用户开启jupyter-notebook服务

一些高效指令

  1. 批量删除编译错误或未指定名字的实验镜像

docker rmi $(docker images | grep "<none>" | awk '//{print $3}')

这个命令同样使用于已经退出的容器,只需修改为

docker rm $(docker container ls -a | grep "Existed" | awk '//{print $1}')


资料引用

Docker

此为docker/singularity(apptainer)使用方法的一些笔记,个人记录使用。

docker三要素

  • 仓库:镜像仓库,镜像的存储库。
  • 镜像:系统镜像等,封装了应用的环境、信息,相当于容器(实例)的类。
  • 容器:由系统镜像(静态配置)生成的应用,可以直接运行镜像中的应用或者使用交互式(类似虚拟机,但占用资源更少)。

docker常见误区

docker并非虚拟机,其本质相当与宿主机的一个进程。在使用docker容器的时候,我们一般一次只运行一个程序,docker执行的程序相当于其第一个进程,当这个进程结束的时候。docker容器也就随之停止。

因此运行docker容器时一定要注意第一个运行的程序一结束,容器便会停止,比如/bin/sh -c command,此时/bin/sh是第一个程序,当此程序运作完毕时,容器也会停止。

docker常用指令

1
docker run 镜像名:tagname 指令1 && [指令2 && [指令3......]]

从指定镜像运行一个容器,若本地没有则从docker hub下载制定镜像,
同时运行容器后的指令,可以通过&&连接符运行多个指令

1
2
docker tag local-image:tagname new-repo:tagname
docker push new-repo:tagname

也可以通过cli方式从本地推送自制的镜像至docker hub(类似于git仓库,可以设置公共仓库和私有仓库)。
不过因为类似一个云端存储,免费版docker用户公共镜像只能有一个

1
docker login

此命令可以登录至docker hub,
之后可以通过docker push发布自己的镜像不过镜像名字必须为用户名/镜像名:标签名

1
docker run -it 指定镜像 /bin/bash 

交互式形式在指定镜像上生成容器并在容器内与容器进行交互。

/bin/bash指定使用的解释器。

1
docker exec -it 容器名 /bin/bash

以交互式形式在指定容器上重新运行指定的解释器。

1
docker search 镜像名

在docker hub上查找有无公开的镜像

1
docker pull 镜像地址

从docker hub上拉取公开的镜像

1
2
3
docker pull
docker commit - 可以提交一个正在运行的容器,通过该容器生成一个我们已经配置好环境的镜像
docker push

这意味着我们可以像使用git一样使用docker处理、更新镜像、容器

docker同时为我们提供了dockerfile,类似一个脚本,在脚本内填入创建镜像需要的指令,docker会自动帮助我们构建所需镜像。

自动构建脚本,相当于自动处理脚本内容在容器内处理,我们再通过容器id提交一个我们自己的镜像(配置了我们的环境)

push 用户名/docker镜像名:tag

其中docker commit可以帮助我们从一个容器中构建出我们自己的镜像,
例如docker commit containerName imageName可以帮助我们使用制定的容器生成自定义的镜像

1
docker build -t [父镜像名]:[镜像的tag] [Dockerfile所在的文件路径]

docker可以从dockerfile(自动构建,描述了使用的镜像还有构建环境需要的目录)中自动构建出一个配置了我们所需要环境的镜像。

--no-cache参数可以指定不使用缓存构建容器

1
sudo cat ubuntu-14.04-x86_64-minimal.tar.gz | docker import - ubuntu:14.04

从本地文件系统(本地系统镜像导入到docker镜像)

1
2
docker images
docker ps / docker ps -a

images列出当前所有镜像列表包括其id
ps列出当前实例化的容器以及其id,有助于我们构建自己的镜像

1
docker container ls -a

列出当前所拥有的容器

需要注意,当我们在交互模式的容器中使用exit或者是ctrl+d退出时,容器会立即终止。
此时我们可以通过docker container start container_id/container_name的方式来重新运行这个容器(之前终端已经退出,之前终端内运行的服务也已被终止)。

docker container restart container_id/container_name重新运行一个容器

1
docker rm container_id/container_name

删除指定的容器

1
docker rmi image_id/image_name

删除指定的镜像

1
docker run -P image

运行一个镜像,随机映射端口

使用docker run -p host_port:container_port image可以指定分配端口,
即我们可以将容器的端口映射至宿主机的端口,通过访问宿主机端口访问容器指定的端口

docker run -d,d参数可以使容器在后台运行

1
docker inspect container_id/container_name

此命令可以获取容器的具体信息

若搭配管道符和文本处理工具可以高效地获取我们需要的信息,
比如docker inspect container_id/container_name | grep IPAddress可以获取容器在宿主机中被分配的id

1
docker run -v host_path/container_path [ -v /other/path:/other/container_path... ]

通过这个命令将宿主机的目录与容器的指定目录进行连接,相当于进行挂载,有助于数据的保存,可以通过这个命令来在宿主机中保存我们需要的日志信息等。多次挂载需要多次进行声明。

1
docker save -o < target_image_name.tar > < current_image_name >

以压缩包保存已经拉取的镜像

1
docker load -i < target_image_name.tar >

加载本地镜像(压缩包形式)

命令行使用

docker cli 的使用前需要先启动docker的守护进程

1
2
sudo systemctl start docker
sudo systemctl enable docker

使用systemctl启动docker和启用docker服务开机自启

细节

很多时候我们不用root账户来运行docker的相关服务,因为安全性很难得到保证。
因此我们需要使用普通用户来使用docker的服务。

在linux中,我们可以这么做:

  1. sudo gpasswd -a username docker
  2. newgrp docker

即将用户添加至docker组,这样可以免去使用sudo,通过root账户运行docker

在使用docker容器的时候,我们一些时候需要在交互模式下跑应用然后退出至我们的宿主机,很多时候我们并不想退出的时候关闭容器,因此我们可以使用快捷键Ctrl+p+q返回宿主机并保证容器能正常运行。

singularity

和docker类似,singularity也提供了类似docker一样的容器服务,也有自己的容器仓库

不过singularity没有镜像的概念,我们运行的都是一个一个容器(容器和镜像不再单独分开)

singularity容器有两种模式(只读、沙盒)

sif文件:压缩后的只读的singularity镜像文件,生产使用主要形式
sandbox:可写的容器,常用于开发或者创建自己的容器

singularity目前常用于高性能计算中,其容器名后缀名.sif。

singularity常用指令

从外部源下载容器

*docker 为docker的镜像仓库 library 为singularity的容器仓库

1
2
singularity -d build 容器名.sif 容器地址
singularity pull 容器名.sif 容器地址

构建沙盒容器

1
2
3
singularity build --sandbox 容器名 容器地址
singularity shell -w[--writeable] 容器名
singularity build 容器名.sif 容器本地地址/

通过Definition文件制作容器

文件名.def

1
singularity build 容器名.sif def文件名.def

运行容器

1
2
singularity exec 容器名.sif/simg bash -c "指令"
singularity shell 容器名.sif - 交互式运行

参考

ArchLinux

前言

近来无事,准备将ArchLinux安装至自己的机子上作为备用系统使用,
也是用于更好地学习Linux系统


正文

ArchLinux的安装

由于个人精力有限,因此其安装过程针对一定的安装环境,实际操作请对照官方文档进行安装

其他相关链接:

  1. ArchLinux社区
  2. 一些Linux启动流程的解析

什么是UEFI,BIOS

BIOS(基本输入输出系统,Basic I/O System),是固化在计算机ROM上的一组程序,这组程序如其名字一样,作为操作系统启动前的步骤为操作系统的正式启动提供:

  1. 加电自检,检测CPU,计时芯片等各种计算机必需设备
  2. 枚举设备,初始化各设备和设备资源
  3. 从CMOS(可读写的RAM芯片,存储一些硬件配置和用户设定参数)中读取数据并进行有关系统设置
    等功能

UEFI(Unified Extensible Firmware Interface,统一可拓展固件接口),其作为一个硬件接口,可用于系统启动,维护的硬件支持。

UEFI的前身是EFI,作为BIOS方案的竞争者,由于早期没有如UEFI一样的接口标准,导致各个厂家的EFI千差万别。

使用了UEFI固件支持的BIOS提供更多的功能如:

  1. 支持2TB以上的硬盘
  2. 支持GPT分区(传统的MBR格式最多支持四个主分区,若要更多的分区需要逻辑分区)等

同时UEFI并没有传统BIOS的自检流程(传统启动方式称为Legacy),因此可以提供更为快速的启动速度。

什么是文件系统(filesystem)

文件系统的概念针对我们日常生活中所使用的各种存储设备如硬盘,USB,光盘等。

无论是我们日常所编写的文本文档,还是计算机程序,抑或是操作系统本身,都是一个文件,存储在我们使用的存储设备当中。

但是存储设备本身并没有特定的结构,整体就是存储单元的集合。而文件的调用,操作系统的引导都需要一种特定的结构去找到存储设备中对应的文件进行执行,例如索引结构等。

因此我们需要各种不同组织文件的方式,这就是文件系统

文件系统提供了各种文件在硬盘上的组织、存放方式,规定了文件本身的属性如文件名最大长度等。同时将数据结构的记录存储至存储设备上,使存储设备逻辑上具有所谓的文件系统

什么是分区表(MBR,GPT)

现今存储设备的容量已经大大提高,1TB的硬盘已经变得司空见惯。

而我们实际生活使用的过程中,由于各种需要,常对硬盘进行分区。

比如重要文件存放至分区1,其余文件存放至分区2。又或者系统1(作为一个文件)存放至分区3,系统2存放至分区4。

因此分区表就是为了对硬盘进行分区(逻辑意义上),并提供分区索引,分区信息存储等功能。

分区表存放于每一个分区的开始部分,提供了该分区的起始扇区,终止扇区,文件系统,下一个分区的索引等。

mbr格式的分区表由于其所占存储空间有限,最多只能支持2TB的存储空间,且每一个设备最多划分出4个主分区。

超出4个需要使用逻辑分区支持。

而gpt格式的分区表存储空间更大,因此可以提供更多的信息,支持9.2ZB的存储空间,且可以存储更多的分区信息而无需划分出逻辑分区。

什么是grub,syslinux(BootLoader)

Grub和Syslinux(只能启动Linux系统)等都是一种系统引导程序(Bootloader),本身也作为一个文件存储于设备之中。

UEFI或者BIOS会识别对应的分区并加载对应的程序,当BootLoader加载之后可以根据已有的配置加载已有的系统

类似Grub和Elilo等的BootLoader有针对UEFI和BIOS有相应的版本,安装时根据自己主板的型号进行选择。

需要注意的是,BIOS版本的BootLoader存放于boot分区(fdisk),UEFI版本的BootLoader存放于EFI分区(EFI文件系统,EFI System)

现在来安装一个ArchLinux

安装时间:2021.09.26

本机安装环境:

  1. 系统存储于外置硬盘
  2. 通过U盘启动盘安装
  3. x86_64芯片架构

下载ArchLinux镜像

下载地址:官网

制作启动盘

Windows下:

可以使用DiskGenius或者Windows自带的设备管理器进行分区

分区完毕后可以使用UltralISO进行启动盘的制作

Linux下:

dd if=(source file name) of=(target file name) (Options)

使用dd命令将镜像文件拷贝至对应U盘设备

根据主板型号进入BIOS/UEFI并选择U盘启动

通常使用F2Esc进入,不同型号的主板可能有所差异,请以主板制造商说明为准。

存储设备分区

*注:若无特殊说明,/dev/xxx统一为与挂载,分区等操作对应的设备分区

使用fdisk -l查看各个存储设备和编号

若为UEFI启动:使用gdisk /dev/xxx(设备编号)命令进行gpt格式的分区

同时需要注意预留500MB以上的EFI分区,swap分区建议为内存大小或者两倍内存大小

若为BIOS启动:使用fdisk /dev/xxx(设备编号)命令进行mbr格式的分区

需要启动一个boot分区

初始化文件系统

  • mkfs.vfat /dev/xxx 或者 mkfs.fat -F32 /dev/xxx 设置EFI分区(若需要的话)
  • mkfs.ext4 /dev/xxx 对需挂载根目录等的分区进行ext4文件系统的格式化
  • mkswap /dev/xxx 设置交换分区
  • swapon /dev/xxx 开启交换分区

挂载分区

由于我们需要从U盘进入我们安装的系统进行操作,因此需要先进行分区的挂载

我们挂载至/mnt分区下,此分区适用于挂载其他系统并对其进行操作。

由于我们刚格式化分区,因此系统以及相关组件并未被安装,并没有类似/home等目录

因此我们手动建立文件夹并进行相应的挂载

  • mount /dev/xxx /mnt 挂载根分区
  • mkdir /mnt/boot 建立boot目录,若为BIOS/MBR启动,此时可以进行mount /dev/xxx /mnt/boot
  • mkdir /mnt/boot/EFI 建立EFI目录,若为UEFI/GPT启动,此时可以进行mount /dev/xxx /mnt/boot/EFI
  • mkdir ...
  • mount ...
  • 直到全部分区正确挂载完毕

下载基本Linux系统和必要组件

格式化的分区并没有基本的Linux系统和组件,因此需要下载

如果下载过程中遇到下载速度慢或者中断等问题,请查看源设置:

打开 /etc/pacman.d/mirrorlist 并添加

  • 兰大镜像源
    Server = https://mirror.lzu.edu.cn/archlinux/$repo/os/$arch
  • 清华镜像源
    Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch

或者其他国内镜像源

然后刷新源

pacman -Syy

下载基本系统和组件

pacstrap /mnt base linux linux-firmware

pacstrap 是Arch提供的脚本,用于安装一些基础软件

实际使用时可以再安装vim nano等文本编辑器软件方便之后的配置文件的更改

生成fstab

fstab用于在加载linux系统时提供分区挂载的信息,缺少此文件或者配置出错将会导致系统无法进入甚至崩溃。

ArchLinux下提供了自动生成目录表的工具genfstab

具体使用:

genfstab -U /mnt >> /mnt/etc/fstab

-U 参数表示使用设备的UUID进行挂载

UUID是一个设备的绝对地址(理论上会产生冲突,但实际情况下发生冲突的可能性可以忽略不记)

>> 表示将前部分的输出写入后部分对应的文件

从U盘进入系统

arch-chroot /mnt

设置时间

设置时区

ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

同步时间

hwclock –systohc

可以使用ntp进行时间的同步。

修改主机名

建立 /etc/hostname 文件写入主机名

更改语言

修改 /etc/locale.gen 文件将需要的字符集前的注释 # 删去

建立 /etc/locale.conf 文件写入

LANG=en_US.UTF-8

*官方wiki中推荐的是先使用en_US.UTF-8,以便终端界面能够正常显示

运行 locale-gen 使语言设置生效

修改网络设置

修改 /etc/hosts 文件写入

127.0.0.1 localhost

::1 localhost

127.0.0.1 主机名.localdomain 主机名

安装网络相关的包

由于ArchLinux秉持轻量化,因此基本系统中并未包括我们常用的网络资源管理相关的软件,需要自行下载。

pacman -S iw wpa_supplicant dialog dhcpcd

*dhcpcd 用于设置ip,如果使用 ip wpa_supplicant dhcpcd 方式配置网络需要安装

安装引导程序(bootloader)

BIOS/MBR

grub-install –target=i386-pc /dev/xxx (这里为boot分区挂载的设备)

grub-mkconfig -o /boot/grub/grub.cfg 根据grub配置更改grub相应参数(可自定义)

UEFI/GPT

pacman -S grub efibootmgr

grub-install –target=x86_64-efi –efi-directory=/boot/EFI –bootloader-id=grub

grub-mkconfig -o /boot/grub/grub.cfg

initramfs生成

由于Linux系统的启动需要同时启动必要的组件,而某些组件之间又相互依赖,或者存在兼容性问题。

为了解决这些问题,Linux在真正的系统启动前需要启动initramfs,即initram file system,用于提供一个用户态的环境以完成内核不易完成的操作,比如加载必要的模块等

使用mkinitcpio -P打包initramfs

关于/usr分区独立进行挂载的问题

在目前的ArchLinux中,/sbin 链接至 /usr/sbin 当我们将/usr分区独立挂载后,会导致initramfs无法找到相应的文件导致启动失败

解决方法:

  1. 修改/etc/fstab文件找到/usr分区一行,将pass参数设置为0
  2. 修改/etc/mkinitcpio.conf文件,在HOOK中添加shutdown和usr

然后重新打包initramfs

mkinitcpio -P

修改root密码

passwd

退出当前系统

exit

解除挂载

umount -R /mnt (从根目录递归解除挂载)

重启进入系统

reboot

ArchLinux系统的配置

网络配置

*使用 ip+wpa_supplicant+dhcpcd 方式

启用网络接口

lspci | grep Network

查看网卡设备是否能被识别到

ip link

查看网络借口名称

*lo表示本地,wl开头表示无线网络接口,en开头表示有线网络接口

ip link set 接口名称 up

启用指定网络接口

使用wpa_supplicant连接无线网络

建立 /etc/wpa_supplicant/wpa_supplicant.conf 文件,写入

ctrl_interface=/run/wpa_supplicant

update_config=1

查看网络设备ifconfig

*本人的网络设备是wlan0

根据配置设置wpa_supplicant

wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf

网络设置

*一下为需要执行的命令,具体参数请根据自己的网络状态配置

wpa_cli

scan
scan_results
add_network
set_network 0 ssid “MYSSID”
set_network 0 psk “passphrase”
enable_network 0
save_config

由此配置完毕,之后可以于/etc/wpa_supplicant/wpa_supplicant.conf修改网络配置

systemctl enable wpa_supplicant.service

启用wpa_supplicant,当存在网络时自动连接,同时启用dhcpcd(systemctl enable dhcpcd)

dhcpcd设置ip

dhcpcd 接口名称

自动获取ip

GRUB引导多系统

UEFI/GPT下引导Windows

查看Win10启动分区(EFI分区)UUID,首先使用fdisk -l查看是哪个分区,比如是/dev/sda1

使用blkid /dev/sda1查看分区的UUID

修改 /boot/grub/grub.cfg 文件

找到 ### BEGIN /etc/grub.d/30_os-prober

添加Windows启动项

1
2
3
4
5
6
7
menuentry 'Microsoft Windows 10'  {
insmod part_gpt
insmod fat
insmod chain ## 链式加载
search --fs-uuid --no-floppy --set=root XXXX-XXXX ## EFI分区的UUID
chainloader (${root})/EFI/Microsoft/Boot/bootmgfw.efi
}

重启进入Grub引导界面查看效果

*如果没有发现Windows启动项,请试着修改 /etc/default/grub 文件

在文件中添加

GRUB_DISABLE_OS_PROBER=false

之后重新配置grub(已被发现则无需配置)

  1. 在Arch下是grub-mkconfig -o /boot/grub/grub.cfg
  2. 在一些系统下是update-grub

请以安装的系统提供的grub文档为准

安装音频支持

*本人对音频安装需要解决:声卡内核驱动的安装,解除声卡静音,设置默认声卡

声卡内核驱动的安装

使用 高级Linux声音体系(Advanced Linux Sound Architecture,ALSA) 提供声卡的内核驱动

pacman -S alsa-utils

安装软件包,用来设置声音

解除声卡静音

alsamixer

进入声音管理界面调节声音,MM表示静音,使用m命令接触静音

speaker-test -c 8

检查是否正常输出声音,若没有声音输出或错误,可能是默认声卡配置的原因

aplay -L | grep :CARD

获取声卡的信息,:=前的名称为声卡的名称

speaker-test -D default:名称 -c 8

由上面的信息指定使用声卡名称进行测试

设置默认声卡

我们通过上述步骤获取声卡信息,其中包括声卡的编号,此时我们需要设置默认的声卡

建立 /etc/asound.conf 或者 ~/.asoundrc 文件,在文件中键入

1
2
defaults.pcm.card 编号
defaults.ctl.card 编号

保存退出,再次测试可以更改默认声卡

可以安装图形化音频调节kmix

目前我使用的音量调节程序:

alsamixer - cli界面调节音量

amixer - amixer set Master 50 , 调节主音量为50

kmix - 图形化界面调节音量

使linux支持挂载ntfs文件系统(微软使用)

pacman -S ntfs-3g

安装之后连接对应存储设备,可以直接使用mount命令挂载

安装中文输入法

首先安装输入法引擎,然后再安装对应语言的输入法。

pacman -S fcitx

安装fcitx输入法引擎

pacman -S fcitx-sunpinyin

安装一个中文输入法

pacman -S fcitx-im

安装输入法组件,以支持各种应用

pacman -S fcitx-configtool

图形化设置fcitx

同步时间

pacman -S ntp

安装ntp软件包

ntpd -u ntp:ntp

使用ntp

ntpq -p

启动时启用ntpd,用来同步时间

ArchLinux系统的美化

grub theme

grub作为引导程序,支持定制化,因此可以制作个性化的启动页面主题。

grub主题资源:

  1. Gnome-look
  2. Opendesktop.org

自定义安装:

  1. 首先将主题文件放置到系统grub主题文件夹中
  2. Arch下可以是/boot/grub/themes/,也可以是/usr/share/grub/themes/
  3. 修改 /etc/default/grub 文件,修改GRUB_THEME=对应主题目录/themes.txt
  4. 重启系统查看效果

中文字体的支持和安装

我们在/etc/locale.gen指定的是支持的字符集,但是除了字符集,我们还需要图形码来支持正常显示文字,也就是安装对应的字体。

Wiki ArchLinux的字体列表中,我们可以查看相应的字体并进行查看。

这里我下载安装两种字体,具体的应用会使用不同的字体。

pacman -S wqy-zenhei adobe-source-han-sans-otc-fonts

使用fc系列命令管理字体(请自行研究)


资料引用

  1. 什么是UEFI和BIOS
  2. 简单分析UEFI
  3. 文件系统
  4. 鸟哥的Linux私房菜
  5. ArchLinux安装(UEFI)
  6. ArchLinux Wiki上的mkinitcpio解释
  7. Linux Grub引导程序的主题美化
  8. ArchLinux Wiki上的wpa_supplicant解释
  9. Grub双系统配置
  10. os-prober错误配置导致多系统引导出错
  11. ArchLinux Wiki上的声音设备配置教程
  12. ArchLinux Wiki上输入法的安装
  13. ArchLinux Wiki上时间同步程序ntp的安装

VimLearn

Just for personal learning and some notes


What

Vim is a mode text editor which has many modes
including Normal Mode, Insert Mode etc.

Each mode has its own functions and operations.

The normal mode in Vim is like a language, that we have different operations,
hava different concepts and commands,
and we can combine them to better edit our file in command line mode.

  • the conclusion from the video that introduces the Vim

The combination of commands are like [extra_param][command]

Mode

  • Normal Mode -> with key ‘i’ -> Insert Mode
  • Normal Mode -> with key ‘R’ -> Replace Mode
  • Normal Mode -> with key ‘v’ -> Visual Mode
  • Normal Mode -> with key ‘Shift V’ -> Visual Mode lmo
  • Normal Mode -> with key ‘Ctrl V’ -> Visual Mode block
  • Normal Mode -> with key ‘:’ -> Command-line Mode

Vim Command

‘:help command’ - list the introductions of the command

We should know that in Vim, the command ‘:w’ and the command ‘w’ is different.
The first is the vim command, and the second is just a command in normal mode

When we enter the introduction, we can use ‘:q’ to quit and back to our open file.
Like we open another file which includes the introductions of the command.

‘:w’ - save the file

‘:q’ or ‘:quit’ - quit the current window not the whole vim

In vim, there is concept of ‘window’ such as when we use ‘:sp’ command to split window,
or use ‘:help’ to open the window which contents the introduction of the command.
When we open this window, we can use ‘:q’ to quit them and back to our open file.

‘:qa’ - quit all, this is the command to quit the vim, or we can say, quit all windows.

‘:set number’ - set line number

This is a vim command to put line number to better edit the file,
the usage of this we can use ‘: set number’ to temporary set the number,
once we need to put line number every time we open the file with vim,
we can add a file named ‘.vimrc’ (vim reconfigure) in our home directory ‘~/.vimrc’,
and put ‘set number’ to it, then next time we use vim we will find the line number.

‘:sp’ - split screen, split the current text screen so we can see mutil screens that shows the text.

‘:set sw’ - set the spaces which indent includes

‘/search’ - search command ‘/‘ can help us move to the position of searched words.
For example, ‘/is’ is to search the words “is”

Movement

these movements command can be used in normal mode

‘j’ - moves down
‘K’ - moves up
‘h’ - moves left
‘g’ - moves right
‘b’ - moves one word backward
‘e’ - moves to the end of a word
‘0’ - moves to the head of the line
‘^’ - the same effect as ‘0’ does
‘$’ - moves to the end of the line
‘^U’ - hold up, switch to up page
‘^D’ - hold down, swicth to down page
‘G’ - moves to the end of the buffers(file)
‘gg’ - moves to the head of the buffers(file)
‘L’ - Lowest, moves to the end of current page
‘M’ - Middle, moves to the middle of current page
‘H’ - Highest, moves to the top of current page
‘F[word to be found]’ - find the fisrt word that equals to the find param we give,
and the moves to that place. Note that this command’s range is limited to the current line.

Like we see in the conclusion,
this command abstracts our moving operations as commands in normal mode.

Thus we can combine these with other operations to help us move faster in the file,
such ‘3j’ command in normal mode can help us move 3 lines one time.

Text Command

Special Text

‘^’ - The start of one line
‘$’ - The end of one line

Normal Mode

‘X’ - Delete one Character where cursor is on.

‘v’ + cursor move - select the text you have selected

‘y(yank)’ - copy the select text

It’s a command which we can use it to copy the text, we can also use ‘yy’ to copy the whole line.
‘[number]yy’ is a special command which can help us copy the next [number] lines from the current line(includes the current line).
‘yw’ can copy the current word.

‘p(paste)’ - paste the copy line to the current position

‘o’ - add a new line after the line where the cursor locates.

‘O’ - add a new line as command ‘o’ and change into the insert mode

‘dd’ - delete the current line

‘u’ - undo the last change you did including actions in insert mode

‘di[parentheses]’ - for example, when cursor is in words “[htt//sfsdfdfa]”,
we can use ‘di[‘ command to delete the content which is included in the “[]”

‘da[parentheses]’ - delete all include the parenthese itself

Visual Mode

When we enter the key ‘v’ in normal mode, we will be in the state of ‘Visual Mode’.
This mode can help us select mutil words, then we can use ‘y’ or ‘p’ to operate on these words.
Or we can just operate one word one time.

‘V’ - when we use this command in Visual Mode or Normal Mode,
we can now select a whole line once we move

‘^V’ - when we use this command, we will enter the ‘visual block mode’,
which we can select a rectangular blocks of text.

Special Command

^V : Ctrl-V :

Expand Reading

Vim offers 12 clipboards which are “0,”1,”2……”9,”” ,
we can use ‘:reg’ in normal to check the content in clipboard,
the default clipboard is “” and “0,
we can use ‘“Ny’ in Visual Mode(^V) to copy the selected text to a clipboard

In conclusion, we can place ‘p’, ‘y’ or something else with ‘“Np’…,
the meaning is that we can copy or paste to and from different clipboards.


Settings for VIM

There are ways to set the VIM:

  1. System setting files are located in /etc/.vimrc
  2. User setting files are located in ~/.vimrc (priority is higher than system)

We can use command :set all in VIM to check the settings.

Reference

正则表达式自查

正则表达式

  • regular expression

正则表达式通过元字符+普通字符组成的字符串来匹配目标字符串中符合表达式规则的子串,常用于字符串的修改,子串的提取等

仅为个人学习记录,一般都是现查现用(

普通字符

包括没有显式指定为元字符的所有可打印和不可打印的字符,包括所有大写、小写字母,所有数字,所有标点符号和其他一些符号

非打印字符

\f 换页符

匹配

[]内表示需要被匹配的字符,需要注意正则表达式实际上是一个字符一个字符的进行匹配,添加适当的规则(元字符+待匹配字符)可以实现匹配子串等作用,而这元字符和待匹配字符构成的规则可以称为一个表达式,即方括号内语句,”中括号“表达式,0-9表示的其实是0-9中的一个字符

?= ?<= ?! ?<!>

exp1(?=exp2) 查找exp2前面的exp1

(?<=exp2)exp1 查找exp2后面的exp1

exp1(?!exp2) 查找后面不是exp2的exp1

(?<!exp2)exp1 查找前面不是exp2的exp1

运算符优先级

匹配符号 含义
\ 转义符
(), (?: ), (?=), [] 圆括号和方括号
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \任何元字符、任何字符 定位点和序列(即:位置和顺序)
字符具有高于替换运算符的优先级,使得”m food”匹配”m”或”food”。若要匹配”mood”或”food”,请使用括号创建子表达式,从而产生”(m

请我喝杯咖啡吧~

支付宝
微信