第三周博客作业

hhh

文本编辑工具之神VIM

vi和vim简介

在Linux中我们经常编辑修改文本文件,即由ASCII, Unicode 或其它编码的纯文字的文件。之前介绍过nano,实际工作中我们会使用更为专业,功能强大的工具
文本编辑种类:

  • 全屏编辑器:nano(字符工具), gedit(图形化工具),vi,vim
  • 行编辑器:sed

vi
Visual editor,文本编辑器,是 Linux 必备工具之一,功能强大,学习曲线较陡峭,学习难度大
vim
VIsual editor iMproved ,和 vi 使用方法一致,但功能更为强大,不是必备软件
官网:www.vim.org
其他相关编辑器:gvim 一个Vim编辑器的图形版本

使用 vim 初步

vim 命令格式

vim [OPTION]... FILE...

常用选项

+# 打开文件后,让光标处于第#行的行首,+默认行尾
+/PATTERN 让光标处于第一个被PATTERN匹配到的行行首
-b file 二进制方式打开文件
-d file1 file2… 比较多个文件,相当于 vimdiff
-m file 只读打开文件
-e file   直接进入ex模式,相当于执行ex file

说明:

  • 如果该文件存在,文件被打开并显示内容
  • 如果该文件不存在,当编辑后第一次存盘时创建它

三种主要模式和转换

vim 是 一个模式编辑器,击键行为是依赖于 vim的 的“模式”
三种常见模式:

  • 命令或普通(Normal)模式:默认模式,可以实现移动光标,剪切/粘贴文本
  • 插入(Insert)或编辑模式:用于修改文本
  • 扩展命令(extended command )或命令(末)行模式:保存,退出等
    模式转换
  • 命令模式 --> 插入模式
i insert, 在光标所在处输入
I 在当前光标所在行的行首输入
a append, 在光标所在处后面输入
A 在当前光标所在行的行尾输入
o 在当前光标所在行的下方打开一个新行
O 在当前光标所在行的上方打开一个新行
  • 插入模式 --- ESC-----> 命令模式
  • 命令模式 ---- : ----> 扩展命令模式
  • 扩展命令模式 ----ESC,enter----> 命令模式

扩展命令模式

按“:”进入Ex模式 ,创建一个命令提示符: 处于底部的屏幕左侧

扩展命令模式基本命令

w 写(存)磁盘文件
wq 写入并退出
x 写入并退出
X   加密
q 退出
q! 不存盘退出,即使更改都将丢失 
r   filename 读文件内容到当前文件中
w   filename 将当前文件内容写入另一个文件
!command 执行命令
r!command 读入命令的输出

地址定界

格式:

:start_pos,end_pos CMD

地址定界格式

# 		#具体第#行,例如2表示第2行
#,# 	#从左侧#表示起始行,到右侧#表示结尾行 
#,+# 	#从左侧#表示的起始行,加上右侧#表示的行数,范例:2,+3 表示2到5行
.   	#当前行
$ 		#最后一行
.,$-1 	#当前行到倒数第二行
% 		#全文, 相当于1,$

/pattern/   	#从当前行向下查找,直到匹配pattern的第一行,即:正则表达式
/pat1/,/pat2/ 	#从第一次被pat1模式匹配到的行开始,一直到第一次被pat2匹配到的行结束
#,/pat/    		#从指定行开始,一直找到第一个匹配patttern的行结束
/pat/,$    		#向下找到第一个匹配patttern的行到整个文件的结尾的所有行

地址定界后跟一个编辑命令

d       #删除
y 		#复制
w file 	#将范围内的行另存至指定文件中
r file 	#在指定位置插入指定文件中的所有内容

查找并替换

格式

s/要查找的内容/替换为的内容/修饰符

说明:

要查找的内容:可使用基末正则表达式模式
替换为的内容:不能使用模式,但可以使用\1, \2, ...等后向引用符号;还可以使用“&”引用前面查找时查找到的整个内容

修饰符:

i #忽略大小写
g #全局替换,默认情况下,每一行只替换第一次出现
gc #全局替换,每次替换前询问

查找替换中的分隔符/可替换为其它字符,如:#,@

定制vim的工作特性

扩展命令模式的配置只是对当前vim进程有效,可将配置存放在文件中持久保存
配置文件:

/etc/vimrc #全局
~/.vimrc #个人

行号

显示:set number,简写 set nu
取消显示:set nonumber, 简写 set nonu

忽略字符的大小写

启用:set ignorecase,简写 set ic
不忽略:set noic

自动缩进

启用:set autoindent,简写 set ai
禁用:set noai

复制保留格式

启用:set paste
禁用:set nopaste

显示Tab和换行符 ^I 和$显示

启用:set list
禁用:set nolist

高亮搜索

启用:set hlsearch
禁用:set nohlsearch

语法高亮

启用:syntax on
禁用:syntax off

文件格式

启用windows格式:set fileformat=dos
启用unix格式:set fileformat=unix
简写 set ff=dos|unix

设置文本宽度

set textwidth=65 (vim only)
set wrapmargin=15

设置光标所在行的标识线

启用:set cursorline,简写 set cul
禁用:set nocursorline

加密

启用: set key=password
禁用: set key=

了解更多

set 帮助
:help option-list
:set or :set all

命令模式

命令模式,又称为Normal模式,功能强大,只是此模式输入指令并在屏幕上显示,所以需要记忆大量的快捷按键才能更好的使用

退出VIM

ZZ 保存退出
ZQ 不保存退出

光标跳转

字符间跳转:
h: 左 L: 右 j: 下 k: 上

COMMAND:跳转由#指定的个数的字符

单词间跳转:
w:下一个单词的词首
e:当前或下一单词的词尾
b:当前或前一个单词的词首

COMMAND:由#指定一次跳转的单词数

当前页跳转:
H:页首 M:页中间行 L:页底
zt:将光标所在当前行移到屏幕顶端
zz:将光标所在当前行移到屏幕中间
zb:将光标所在当前行移到屏幕底端
行首行尾跳转:
^ 跳转至行首的第一个非空白字符
0 跳转至行首
$ 跳转至行尾
行间移动:

G 或者扩展命令模式下 :# 跳转至由第#行

G 最后一行
1G, gg 第一行
句间移动:
) 下一句 ( 上一句
段落间移动:
} 下一段 { 上一段
命令模式翻屏操作
Ctrl+f 向文件尾部翻一屏
Ctrl+b 向文件首部翻一屏
Ctrl+d 向文件尾部翻半屏
Ctrl+u 向文件首部翻半屏

字符编辑

x 删除光标处的字符

x 删除光标处起始的#个字符

xp 交换光标所在处的字符及其后面字符的位置
转换大小写

J 删除当前行后的换行符

替换命令(replace)

r 只替换光标所在处的一个字符
R 切换成REPLACE模式(在末行出现-- REPLACE -- 提示),按ESC回到命令模式

删除命令(delete)

d 删除命令,可结合光标跳转字符,实现范围删除
d$ 删除到行尾
d^ 删除到非空行首
d0 删除到行首
dw
de
db

COMMAND

dd: 剪切光标所在的行

dd 多行删除

D:从当前光标位置一直删除到行尾,等同于d$

复制命令(yank)

y 复制,行为相似于d命令
y$
y0
y^
ye
yw
yb

COMMAND

yy:复制行

yy 复制多行

Y:复制整行

粘贴命令(paste)

p 缓冲区存的如果为整行,则粘贴当前光标所在行的下方;否则,则粘贴至当前光标所在处的后面
P 缓冲区存的如果为整行,则粘贴当前光标所在行的上方;否则,则粘贴至当前光标所在处的前面

改变命令(change)

c: 删除后切换成插入模式
c$
c^
c0
cb
ce
cw

COMMAND

cc:删除当前行并输入新内容,相当于S

cc

C:删除当前光标到行尾,并切换成插入模式,相当于c$

查找

/PATTERN:从当前光标所在处向文件尾部查找
?PATTERN:从当前光标所在处向文件首部查找
n:与命令同方向
N:与命令反方向

撤消更改

u 撤销最近的更改,相当于windows中ctrl+z

u 撤销之前多次更改

U 撤消光标落在这行后所有此行的更改
Ctrl - r 重做最后的“撤消”更改,相当于windows中crtl+y
. 重复前一个操作

. 重复前一个操作#次

高级用法

<start position><command><end position>
常见Command:y 复制、d 删除、gU 变大写、gu 变小写
范例:

0y$ 命令
0 → 先到行头
y → 从这里开始拷贝
$ → 拷贝到本行最后一个字符

范例:粘贴“wang”100次

100iwang [ESC]

di" 光标在” “之间,则删除” “之间的内容
yi( 光标在()之间,则复制()之间的内容
vi[ 光标在[]之间,则选中[]之间的内容
dtx 删除字符直到遇见光标之后的第一个 x 字符
ytx 复制字符直到遇见光标之后的第一个 x 字符

可视化模式

在末行有”-- VISUAL -- “指示,表示在可视化模式
允许选择的文本块

  • v 面向字符,-- VISUAL --
  • V 面向整行,-- VISUAL LINE --
  • ctrl-v 面向块,-- VISUAL BLOCK --
    可视化键可用于与移动键结合使用
    w ) } 箭头等
    突出显示的文字可被删除,复制,变更,过滤,搜索,替换等
    范例:在文件行首插入#
输入ctrl+v 进入可视化模式
输入 G 跳到最后1行,选中每一行的第一个字符
输入 I 切换至插入模式
输入 # 
按 ESC 键

多文件模式

vim FILE1 FILE2 FILE3 ...
:next 下一个
:prev 前一个
:first 第一个
:last 最后一个
:wall 保存所有
:qall 不保存退出所有
:wqall保存退出所有

多窗口模式

多文件分割

vim -o|-O FILE1 FILE2 ...
-o: 水平或上下分割
-O: 垂直或左右分割(vim only)
在窗口间切换:Ctrl+w, Arrow

单文件窗口分割

Ctrl+w,s:split, 水平分割,上下分屏
Ctrl+w,v:vertical, 垂直分割,左右分屏
ctrl+w,q:取消相邻窗口
ctrl+w,o:取消全部窗口
:wqall 退出

vim的寄存器

有26个命名寄存器和1个无命名寄存器,常存放不同的剪贴版内容,可以在同一个主机的不同会话(终
端窗口)间共享
寄存器名称a,b,…,z,格式: ”寄存器 放在数字和命令之间
范例:
3"tyy 表示复制3行到t寄存器中 ,末行显示 3 lines yanked into "t
"tp 表示将t寄存器内容粘贴
未指定,将使用无命名寄存器
有10个数字寄存器,用0,1,…,9表示,0存放最近复制内容,1存放最近删除内容。当新的文本变更和删除时,1转存到2,2转存到3,以此类推。数字寄存器不能在不同会话间共享

标记和宏(macro)

ma 将当前位置标记为a,26个字母均可做标记, mb 、 mc 等等
'a 跳转到a标记的位置,实用的文档内标记方法,文档中跳跃编辑时很有用
qa 录制宏 a,a为宏的名称,末行提示: recording @a
q 停止录制宏
@a 执行宏 a
@@ 重新执行上次执行的宏

编辑二进制文件

#以二进制方式打开文件
vim -b binaryfile
#扩展命令模式下,利用xxd命令转换为可读的十六进制
:%!xxd
#切换至插入模式下,编辑二进制文件
#切换至扩展命令模式下,利用xxd命令转换回二进制
:%!xxd  -r
#保存退出

文本常见处理工具

文件内容查看命令

查看文本文件内容

cat

cat 可以查看文本内容
格式:

cat [OPTION]... [FILE]...

常见选项
-E:显示行结束符$
-A:显示所有控制符
-n:对显示出的每一行进行编号
-b:非空行编号
-s:压缩连续的空行成一行

nl

显示行号,相当于cat -b

[root@centos8 ~]#nl /data/f1.txt
     1 a
     2 b
     3 c
     4 d
     5 e
     6 f
     7 g
     8 h

tac

逆向显示文本内容

[root@centos8 ~]#seq 10 |tac
10
9
8
7
6
5
4
3
2
1

rev

将同一行的内容逆向显示

[root@centos8 ~]#echo {1..10} |rev
01 9 8 7 6 5 4 3 2 1

查看非文本文件内容

hexdump

echo {a..z} | tr -d ' '|hexdump -C
00000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 |abcdefghijklmnop|
00000010 71 72 73 74 75 76 77 78 79 7a 0a                 |qrstuvwxyz.|
0000001b

od

od 即 dump files in octal and other formats

[root@centos8 ~]#echo {a..z} | tr -d ' '|od -t x
0000000 64636261 68676665 6c6b6a69 706f6e6d
0000020 74737271 78777675 000a7a79
0000033

xxd

echo {a..z} | tr -d ' '|xxd 
0000000: 6162 6364 6566 6768 696a 6b6c 6d6e 6f70 abcdefghijklmnop
0000010: 7172 7374 7576 7778 797a 0a             qrstuvwxyz.

分页查看文件内容

more

可以实现分页查看文件,可以配合管道实现输出信息的分页
格式

more [OPTIONS...] FILE...

选项:
-d: 显示翻页及退出提示
less 也可以实现分页查看文件或STDIN输出
查看时有用的命令包括:
/文本 搜索 文本
n/N 跳到下一个 或 上一个匹配

less

less 命令是man命令使用的分页器

[root@centos8 ~]#cat /etc/init.d/functions |less 
# -*-Shell-script-*-
#
# functions This file contains functions to be used by most or all
#       shell scripts in the /etc/init.d directory.
#
TEXTDOMAIN=initscripts
# Make sure umask is sane
umask 022
# Set up a default search path.
PATH="/sbin:/usr/sbin:/bin:/usr/bin"
export PATH
...省略...

显示文本前或后行内容

可以显示文件或标准输入的前面行
格式:

head [OPTION]... [FILE]...

选项:
-c # 指定获取前#字节
-n # 指定获取前#行
-# 同上

tail

tail 和head 相反,查看文件或标准输入的倒数行
格式:

tail [OPTION]... [FILE]...

-c # 指定获取后#字节
-n # 指定获取后#行
-# 同上
-f 跟踪显示文件fd新追加的内容,常用日志监控,相当于 --follow=descriptor,当文件删除再新建同名
文件,将无法继续跟踪文件
-F 跟踪文件名,相当于--follow=name --retry,当文件删除再新建同名文件,将可以继续跟踪文件
tailf 类似 tail –f,当文件不增长时并不访问文件

按列抽取文本cut

cut 命令可以提取文本文件或STDIN数据的指定列
格式

cut [OPTION]... [FILE]...

选项
-d DELIMITER: 指明分隔符,默认tab
-f FILEDS:
#: 第#个字段,例如:3
#,#[,#]:离散的多个字段,例如:1,3,6
#-#:连续的多个字段, 例如:1-6
混合使用:1-3,7
-c 按字符切割
--output-delimiter=STRING指定输出分隔符

合并多个文件paste

paste 合并多个文件同行号的列到一行
格式

paste [OPTION]... [FILE]...

-d 分隔符:指定分隔符,默认用TAB
-s : 所有行合成一行显示

分析文本的工具

文本数据统计:wc
整理文本:sort
比较文件:diff和patch

收集文本统计数据wc

wc 命令可用于统计文件的行总数、单词总数、字节总数和字符总数
可以对文件或STDIN中的数据统计

常用选项
-l 只计数行数
-w 只计数单词总数
-c 只计数字节总数
-m 只计数字符总数
-L 显示文件中最长行的长度

文本排序sort

把整理过的文本显示在STDOUT,不改变原始文件
格式:

sort [options] file(s)

常用选项
-r 执行反方向(由上至下)整理
-R 随机排序
-n 执行按数字大小整理
-f 选项忽略(fold)字符串中的字符大小写
-u 选项(独特,unique)删除输出中的重复行
-t c 选项使用c做为字段界定符
-k # 选项按照使用c字符分隔的 # 列来整理能够使用多次

去重uniq

uniq命令从输入中删除前后相接的重复的行
格式:

uniq [OPTION]... [FILE]...

常见选项:
-c: 显示每行重复出现的次数
-d: 仅显示重复过的行
-u: 仅显示不曾重复的行

uniq常和sort 命令一起配合使用:

sort userlist.txt | uniq -c

比较文件

diff

diff 命令比较两个文件之间的区别
diff 命令的输出被保存在一种叫做“补丁”的文件中
使用 -u 选项来输出“统一的(unified)”diff格式文件,最适用于补丁文件

patch

patch 复制在其它文件中进行的改变(要谨慎使用)
适用 -b 选项来自动备份改变了的文件

cmp

[root@centos8 data]#ll /usr/bin/dir /usr/bin/ls 
-rwxr-xr-x. 1 root root 166448 May 12  2019 /usr/bin/dir
-rwxr-xr-x. 1 root root 166448 May 12  2019 /usr/bin/ls
[root@centos8 data]#ll /usr/bin/dir /usr/bin/ls -i
201839444 -rwxr-xr-x. 1 root root 166448 May 12  2019 /usr/bin/dir
201839465 -rwxr-xr-x. 1 root root 166448 May 12  2019 /usr/bin/ls
[root@centos8 data]#diff /usr/bin/dir /usr/bin/ls
Binary files /usr/bin/dir and /usr/bin/ls differ

[root@centos8 ~]#cmp /bin/dir /bin/ls
/bin/dir /bin/ls differ: byte 737, line 2
[root@centos8 ~]#hexdump -s 730 -Cn 7 /bin/dir
000002da  00 00 47 4e 55 00 b0                             |..GNU..|
000002e1
[root@centos8 ~]#hexdump -s 730 -Cn 7 /bin/ls 
000002da  00 00 47 4e 55 00 93                             |..GNU..|
000002e1

正则表达式

REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)
不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配
符功能是用来处理文件名,而正则表达式是处理文本内容中字符
正则表达式被很多程序和开发语言所广泛支持:vim, less,grep,sed,awk, nginx,mysql 等
正则表达式分两类:

  • 基本正则表达式:BRE
  • 扩展正则表达式:ERE
    正则表达式引擎:
    采用不同算法,检查处理正则表达式的软件模块,如:PCRE(Perl Compatible Regular
    Expressions)
    正则表达式的元字符分类:字符匹配、匹配次数、位置锚定、分组
    帮助:man 7 regex

基本正则表达式元字符

字符匹配

.   匹配任意单个字符,可以是一个汉字
[]   匹配指定范围内的任意单个字符,示例:[wang]   [0-9]   [a-z]   [a-zA-Z]
[^] 匹配指定范围外的任意单个字符,示例:[^wang]

[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号

匹配次数

用在要指定次数的字符后面,用于指定前面的字符要出现的次数

* 匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.* 任意长度的任意字符
\? 匹配其前面的字符0或1次,即:可有可无
\+ 匹配其前面的字符至少1次,即:肯定有,>=1
\{n\} 匹配前面的字符n次
\{m,n\} 匹配前面的字符至少m次,至多n次
\{,n\} 匹配前面的字符至多n次,<=n
\{n,\} 匹配前面的字符至少n次

位置锚定

位置锚定可以用于定位出现的位置

^ 行首锚定,用于模式的最左侧
$ 行尾锚定,用于模式的最右侧
^PATTERN$ 用于模式匹配整行
^$ 			空行
^[[:space:]]*$ 空白行
\< 或 \b 词首锚定,用于单词模式的左侧
\> 或 \b 词尾锚定,用于单词模式的右侧
\<PATTERN\> 匹配整个单词

分组其它

分组

分组:() 将多个字符捆绑在一起,当作一个整体处理,如:(root)+
后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: \1, \2, \3, ...
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
注意: 后向引用 引用前面的分组括号中的模式所匹配字符,而非模式本身

或者

或者:|
示例:

a\|b #a或b  
C\|cat #C或cat   
\(C\|c\)at #Cat或cat

扩展正则表达式

字符匹配元字符

. 任意单个字符
[wang] 指定范围的字符
[^wang] 不在指定范围的字符
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号

次数匹配

*   匹配前面字符任意次
? 0或1次
+ 1次或多次
{n} 匹配n次
{m,n} 至少m,至多n次

位置锚定

^ 行首
$ 行尾
\<, \b 语首
\>, \b 语尾

分组其它

() 分组
后向引用:\1, \2, ...
| 或者
a|b	 	#a或b
C|cat 	#C或cat
(C|c)at #Cat或cat

文本处理三剑客

文本处理三剑客之 grep

grep: Global search REgular expression and Print out the line
作用:文本搜索工具,根据用户指定的“模式”对目标文本逐行进行匹配检查;打印匹配到的行
模式:由正则表达式字符及文本字符所编写的过滤条件
格式:

grep [OPTIONS] PATTERN [FILE...]

常见选项:
--color=auto 对匹配到的文本着色显示
-m # 匹配#次后停止
-v 显示不被pattern匹配到的行
-i 忽略字符大小写
-n 显示匹配的行号
-c 统计匹配的行数
-o 仅显示匹配到的字符串
-q 静默模式,不输出任何信息
-A # after, 后#行
-B # before, 前#行
-C # context, 前后各#行
-e 实现多个选项间的逻辑or关系,如:grep –e ‘cat ’ -e ‘dog’ file
-w 匹配整个单词
-E 使用ERE,相当于egrep
-F 不支持正则表达式,相当于fgrep
-f file 根据模式文件处理
-r 递归目录,但不处理软链接
-R 递归目录,但处理软链接

shell 脚本编程

编程基础

Linus:Talk is cheap, show me the code

程序组成

程序:算法+数据结构
数据:是程序的核心
算法:处理数据的方式
数据结构:数据在计算机中的类型和组织方式

程序编程风格

  • 面向过程语言
  • 做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如
  • 果出现了情况B,做什么处理
  • 问题规模小,可以步骤化,按部就班处理
  • 以指令为中心,数据服务于指令
  • C,shell
  • 面向对象语言
  • 一种认识世界、分析世界的方法论。将万事万物抽象为各种对象
  • 类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合
  • 对象是类的具象,是一个实体
  • 问题规模大,复杂系统
  • 以数据为中心,指令服务于数据
  • java,C#,python,golang等

编程语言

计算机:运行二进制指令
编程语言:人与计算机之间交互的语言。分为两种:低级语言和高级语言

  • 低级编程语言:
    机器:二进制的0和1的序列,称为机器指令。与自然语言差异太大,难懂、难写
    汇编:用一些助记符号替代机器指令,称为汇编语言
    如:ADD A,B 将寄存器A的数与寄存器B的数相加得到的数放到寄存器A中
    汇编语言写好的程序需要汇编程序转换成机器指令
    汇编语言稍微好理解,即机器指令对应的助记符,助记符更接近自然语言
  • 高级编程语言:
    编译:高级语言-->编译器-->机器代码文件-->执行,如:C,C++
    解释:高级语言-->执行-->解释器-->机器代码,如:shell,python,php,JavaScript,perl

编程逻辑处理方式

三种处理逻辑

  • 顺序执行
  • 选择执行
  • 循环执行

shell 脚本语言的基本用法

shell 脚本的用途

  • 自动化常用命令
  • 执行系统管理和故障排除
  • 创建简单的应用程序
  • 处理文本或文件

shell脚本基本结构

shell脚本编程:是基于过程式、解释执行的语言
编程语言的基本结构:

  • 各种系统命令的组合

  • 数据存储:变量、数组

  • 表达式:a + b

  • 控制语句:if
    shell脚本:包含一些命令或声明,并符合一定格式的文本文件
    格式要求:首行shebang机制

#!/bin/bash
#!/usr/bin/python 
#!/usr/bin/perl

创建shell脚本过程

第一步:使用文本编辑器来创建文本文件
第一行必须包括shell声明序列:#!
示例:

#!/bin/bash

添加注释,注释以#开头
第二步:加执行权限
给予执行权限,在命令行上指定脚本的绝对或相对路径
第三步:运行脚本
直接运行解释器,将脚本作为解释器程序的参数运行

脚本注释规范

1、第一行一般为调用使用的语言
2、程序名,避免更改文件名为无法找到正确的文件
3、版本号
4、更改后的时间
5、作者相关信息
6、该程序的作用,及注意事项
7、最后是各版本的更新简要说明

第一个脚本

#!SHEBANG
CONFIGURATION_VARIABLES
FUNCTION_DEFINITIONS
MAIN_CODE

脚本调试

只检测脚本中的语法错误,但无法检查出命令错误,但不真正执行脚本

bash -n /path/to/some_script

调试并执行

bash -x /path/to/some_script

总结:脚本错误常见的有三种

  • 语法错误,会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准
    确的
  • 命令错误,后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察
  • 逻辑错误:只能使用 bash -x 进行观察

变量

变量

变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据

变量类型

变量类型:

  • 内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE
  • 用户自定义变量
    不同的变量存放的数据不同,决定了以下
  1. 数据存储方式
  2. 参与的运算
  3. 表示的数据范围
    变量数据类型:
  • 字符
  • 数值:整型、浮点型,bash 不支持浮点数

编程语言分类

静态和动态语言

  • 静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c
  • 动态编译语言:不用事先声明,可随时改变类型,如:bash,Python
    强类型和弱类型语言
  • 强类型语言:不同类型数据操作,必须经过强制转换才同一类型才能运算,如java , c# ,python
    如:以下python代码
    print('magedu'+ 10) 提示出错,不会自动转换类型
    print('magedu'+str(10)) 结果为magedu10,需要显示转换类型
  • 弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会
    自动进行隐式类型转换;变量无须事先定义可直接调用
    如:bash ,php,javascript

Shell中变量命名法则

  • 不能使程序中的保留字:如:if, for
  • 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
  • 见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
  • 统一命名规则:驼峰命名法, studentname,大驼峰StudentName 小驼峰studentName
  • 变量名大写:STUDENT_NAME
  • 局部变量小写
  • 函数名小写

变量定义和引用

变量的生效范围等标准划分变量类型

  • 普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell
    进程均无效
  • 环境变量:生效范围为当前shell进程及其子进程
  • 本地变量:生效范围为当前shell进程中某代码片断,通常指函数
    变量赋值:
name='value'

value 可以是以下多种形式

直接字串:name='root'
变量引用:name="$USER"
命令引用:name=`COMMAND` 或者 name=$(COMMAND)

注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除
变量引用:

$name
${name}  

弱引用和强引用

  • "$name " 弱引用,其中的变量引用会被替换为变量值
  • '$name ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
    显示已定义的所有变量:
set

删除变量:

unset <name>

环境变量

环境变量:

  • 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
  • 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
  • 一般只在系统配置文件中使用,在脚本中较少使用
    变量声明和赋值:
#声明并赋值
export name=VALUE
declare -x name=VALUE
#或者分两步实现
name=VALUE
export name

变量引用:

$name
${name}

显示所有环境变量:

env
printenv
export
declare -x

删除变量:

unset name

bash内建的环境变量

PATH
SHELL
USER
UID
HOME
PWD
SHLVL #shell的嵌套层数,即深度
LANG
MAIL
HOSTNAME
HISTSIZE
_   #下划线 表示前一命令的最后一个参数

只读变量

只读变量:只能声明定义,但后续不能修改和删除,即常量
声明只读变量:

readonly name
declare  -r name

查看只读变量:

readonly [-p]
declare -r

位置变量

位置变量:在bash shell中内置的变量, 在脚本代码中调用通过命令行传递给脚本的参数

$1, $2, ... 对应第1个、第2个等参数,shift [n]换位置
$0 命令本身,包括路径
$* 传递给脚本的所有参数,全部参数合为一个字符串
$@ 传递给脚本的所有参数,每个参数为独立字符串
$# 传递给脚本的参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异

清空所有位置变量

set --

退出状态码变量

当我们浏览网页时,有时会看到下图所显示的数字,表示网页的错误信息,我们称为状态码,在shell脚本中也有相似的技术表示程序执行的相应状态。
进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255

$?的值为0 #代表成功
$?的值是1到255   #代表失败

用户可以在脚本中使用以下命令自定义退出状态码

exit [n]

注意:

  • 脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
  • 如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

展开命令行

展开命令执行顺序

把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配*、?、[abc]等等
准备I/0重导向 <、>
运行命令

防止扩展

反斜线(\)会使随后的字符按原意解释

加引号来防止扩展

单引号(’’)防止所有扩展
双引号(”“)也可防止扩展,但是以下情况例外:$(美元符号)

变量扩展

`` : 反引号,命令替换
\:反斜线,禁止单个字符扩展
!:叹号,历史命令替换

脚本安全和 set

set 命令:可以用来定制 shell 环境
$- 变量
h:hashall,打开选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选项关闭
i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的 shell。所谓的交互式shell,在脚本中,i选项是关闭的
m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等
B:braceexpand,大括号扩展
H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的一个历史命令,“!n”返回第 n 个历史命令
set 命令实现脚本安全
-u 在扩展一个没有设置的变量时,显示错误信息, 等同set -o nounset
-e 如果一个命令返回一个非0退出状态值(失败)就退出, 等同set -o errexit
-o option 显示,打开或者关闭选项
显示选项:set -o
打开选项:set -o 选项
关闭选项:set +o 选项
-x 当执行命令时,打印命令及其参数,类似 bash -x

格式化输出 printf

格式

printf "指定的格式" "文本1" ”文本2“……

常用格式替换符

替换符 功能
%s 字符串
%f 浮点格式
%b 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义
%c ASCII字符,即显示对应参数的第一个字符
%d,%i 十进制整数
%o 八进制值
%u 不带正负号的十进制值
%x 十六进制值(a-f)
%X 十六进制值(A-F)
%% 表示%本身
说明:%s 中的数字代表此替换符中的输出字符宽度,不足补空格,默认是右对齐,%-10s表示10个字符宽,- 表示左对齐
常用转义字符
转义符 功能
---- ----
\a 警告字符,通常为ASCII的BEL字符
\b 后退
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ 表示\本身

算术运算

shell 支持算术运算,但只支持整数,不支持小数
bash中的算术运算

+
-
*
/
% 取模,即取余数,示例:9%4=1,5%3=2
** 乘方

乘法符号有些场景中需要转义
实现算术运算:

(1) let var=算术表达式
(2) var=$[算术表达式]
(3) var=$((算术表达式))
(4) var=$(expr arg1 arg2 arg3 ...)
(5) declare –i var = 数值
(6) echo '算术表达式' | bc

内建的随机数生成器变量:

$RANDOM   取值范围:0-32767

增强型赋值:

+= i+=10 相当于 i=i+10
-= i-=j   相当于 i=i-j
*=
/=
%=
++ i++,++i   相当于 i=i+1
-- i--,--i   相当于 i=i-1

格式:

let varOPERvalue

逻辑运算

true, false
1, 0
与:&:和0相与,结果为0,和1相与,结果保留原值
1 与 1 = 1
1 与 0 = 0
0 与 1 = 0
0 与 0 = 0
或:|:和1相或结果为1,和0相或,结果保留原值
1 或 1 = 1
1 或 0 = 1
0 或 1 = 1
0 或 0 = 0
非:!
! 1 = 0 ! true
! 0 = 1 ! false
异或:^
异或的两个值,相同为假,不同为真。两个数字X,Y异或得到结果Z,Z再和任意两者之一X异或,将得出另一个值Y

1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0

短路运算

  • 短路与
    CMD1 短路与 CMD2
    第一个CMD1结果为 0 (假 ),总的结果必定为0,因此不需要执行CMD2
    第一个CMD1结果为 1 (真),第二个CMD2必须要参与运算,才能得到最终的结果
  • 短路或
    CMD1 短路或 CMD2
    第一个CMD1结果为1 (真),总的结果必定为1,因此不需要执行CMD2
    第一个CMD1结果为0 (假 ),第二个CMD2 必须要参与运算,,才能得到最终的结果

条件测试命令

条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成测
试过程
评估布尔声明,以便用在条件性执行中
若真,则状态码变量 ? 返 回 0 若 假 则 状 态 码 变 量 ? 返回 1
条件测试命令

  • test EXPRESSION
  • [ EXPRESSION ]
  • [[ EXPRESSION ]]
    注意:EXPRESSION前后必须有空白字符

变量测试

-v VAR 变量VAR是否设置
示例:判断 NAME 变量是否定义

[ -v NAME ]

数值测试

-gt 是否大于
-ge 是否大于等于
-eq 是否等于
-ne 是否不等于
-lt 是否小于
-le 是否小于等于

字符串测试

-z "STRING" 字符串是否为空,空为真,不空为假
-n "STRING" 字符串是否不空,不空为真,空为假 
=   是否等于
!=  是否不等于
>   ascii码是否大于ascii码
<   是否小于
==  左侧字符串是否和右侧的PATTERN相同
    注意:此表达式用于[[ ]]中,PATTERN为通配符
=~  左侧字符串是否能够被右侧的PATTERN所匹配
    注意: 此表达式用于[[ ]]中;扩展的正则表达式

文件测试

存在性测试

-a FILE:同 -e
-e FILE: 文件存在性测试,存在为真,否则为假
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件

文件权限测试:

-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限

文件属性测试

-s FILE: 是否存在且非空
-t fd: fd 文件描述符是否在某终端已经打开
-N FILE:文件自从上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组
FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2: FILE1是否旧于FILE2

关于() 和 {}

( list ) 会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境, 帮助参看:man bash 搜索(list)

组合测试条件

第一种方式

[ EXPRESSION1 -a EXPRESSION2 ] 并且
[ EXPRESSION1 -o EXPRESSION2 ] 或者
[ ! EXPRESSION ]               取反

说明: -a 和 -o 需要使用测试命令进行,[[ ]] 不支持

第二种方式

COMMAND1 && COMMAND2 #并且,短路与,代表条件性的AND THEN
如果COMMAND1 成功,将执行COMMAND2,否则,将不执行COMMAND2
COMMAND1 || COMMAND2 #或者,短路或,代表条件性的OR ELSE
如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2
! COMMAND   非,取反

使用read命令来接受输入

使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量
格式:

read [options] [name ...]

常见选项:

-p 指定要显示的提示
-s   静默输入,一般用于密码
-n N 指定输入的字符长度N
-d ‘字符’ 输入结束符
-t N TIMEOUT为N秒

bash的配置文件

bash shell的配置文件很多,可以分成下面类别

按生效范围划分两类

全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
个人配置:
~/.bash_profile
~/.bashrc

shell登录两种方式分类

交互式登录

(1)直接通过终端输入账号密码登录
(2)使用“su - UserName” 切换的用户
配置文件执行顺序:

/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> 
/etc/bashrc

非交互式登录

(1)su UserName
(2)图形界面下打开的终端
(3)执行脚本
(4)任何其它的bash实例
执行顺序:

/etc/profile.d/*.sh --> /etc/bashrc -->~/.bashrc

按功能划分分类

profile类和bashrc类

profile类

profile类为交互式登录的shell提供配置
全局:/etc/profile, /etc/profile.d/*.sh
个人:~/.bash_profile
功用:
(1) 用于定义环境变量
(2) 运行命令或脚本

Bashrc类

bashrc类:为非交互式和交互式登录的shell提供配置
全局:/etc/bashrc
个人:~/.bashrc
功用:
(1) 定义命令别名和函数
(2) 定义本地变量

编辑配置文件生效

修改profile和bashrc文件后需生效两种方法:

  1. 重新启动shell进程
  2. source|. 配置文件
    范例:
. ~/.bashrc

Bash 退出任务

保存在~/.bash_logout文件中(用户),在退出登录shell时运行
功能:

  • 创建自动备份
  • 清除临时文件

流程控制

条件选择

选择执行if语句

格式:

if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else 
COMMANDS; ] fi

单分支

if 判断条件;then
   条件为真的分支代码
fi

双分支

if 判断条件; then
 条件为真的分支代码
else
 条件为假的分支代码
fi

多分支

if 判断条件1; then
 条件1为真的分支代码
elif 判断条件2; then
 条件2为真的分支代码
elif 判断条件3; then
 条件3为真的分支代码
...
else
 以上条件都为假的分支代码
fi

说明:

  • 多个条件时,逐个条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if语句
  • if 语句可嵌套

条件判断case语句

格式:

case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
case 变量引用 in
PAT1)
 分支1
 ;;
PAT2)
 分支2
 ;;
...
*)
 默认分支
 ;;
esac

case支持glob风格的通配符:

*: 任意长度任意字符
?: 任意单个字符
[]:指定范围内的任意单个字符
|:   或,如 a或b
posted @ 2020-04-05 16:04  进击的子卿  阅读(152)  评论(0)    收藏  举报