写在前面
shell脚本是linux运维学习的中的重点和难点,因此把这部分放到最后来整理。主要包括:
shell基础知识
如何编写shell脚本?
采用shell编写linux告警系统
首先是第一部分,shell基础。
什么是shell?
shell 是一种命令解释器,也是一种脚本语言。shell编写的程序成为脚本(script),能够调用所有的UNIX系统命令、实用程序、工具软件,以及二进位制文件;支持循环、判断等特定语法。
目前,常见的shell,还有zsh、ksh等。CentOS 默认安装的shell,叫做bash(Bourne Again Shell),简称sh。
这里先把整理shell作为命令解释器的部分。
命令历史 history
查看命令历史
history
命令可以查看命令历史
1 | [root@stevey ~]# history | less |
history -c
清空内存中的命令历史;
注:
该操作并不会清空
.bash_history
内容。命令历史只有在shell退出的时候,才会保存到
.bash_history
当中。
history配置文件及修改
history配置文件
bash 可以记录命令历史,保存在当前用户家目录下的.bash_history
当中,默认支持1000条,
1 | [root@stevey ~]# head /root/.bash_history //注:当前是root操作 |
如何修改history配置文件?
第一步:编辑配置文件
1 | vim /etc/profile |
第二步:修改配置文件
1 | HISTSIZE=n //n为最大条数,默认1000 |
第三步:source
1 | source /etc/profile |
history永久保存
1 | chmod +a ~/.bash_profile |
注:该配置只对正常退出shell的时候才有效。
与命令历史相关特殊用法
!!
执行上一条命令
!n
n代表数字,执行命令历史中的第n条命令
!$
$
代表上一条命令最后的那个值
![字符串]
字符串最少要有一个字符,比如m表示命令历史中最近的一个以m开头的命令
命令补全tab
及其别名
补全插件安装 tab
- shell的命令补全功能需要先安装插件
1 | root@stevey php-7.2.4]# yum install -y bash-completion |
安装完成后重启电脑,就可以生效了。
alias 别名
终端输入 alias
可以查看当前已经设置的别名
注意:
centos中,别名的配置文件在
~/.bashrc
,也可以通过vim ~/.bashrc
进行编辑设置;也有部分在/etc/profile.d/
下定义。alias
在macos下同样有效,不同在于配置文件在~/.bash_profile
,也可以通过vim ~/.bash_profile
进行编辑设置。
设置别名: alias [别名]=[具体命令]
别名是一个很有用的命令,可以玩出很多花样。比如,可以将平常的工作目录都是设置一个别名,这样就不用每次都输入一长串命令了。
注:
具体命令用英文单引号括起来;
括号两边是没有空格的;
1 | [root@stevey ~]# alias test='cd /root/test/' |
取消别名: unalias [别名]
1 | [root@stevey test]# unalias test |
shell当中的特殊字符
*
用来匹配一个或多个字符
?
用来匹配一个字符。
[m-n]表示范围
注:m、n可以是数字范围,也可以是字母;符合范围中的一个,就可以被匹配出来;
{m,n} 表示范围中的一个,逗号是或的意思
m和n中间用逗号连接,是或的意思,符合范围中的一个可以被匹配出来。
1 | [root@stevey test]# touch {1,3}.txt //创建a.txt和3.txt |
注释符号#
跟js当中的 //
, python中的#
一样,这里也是表示注释的意思,#
后面的内容会被忽略。
1 | [root@stevey ~]# a=2 #sdscsdc //#后面是注释 |
脱义字符 \
比如,*
?
在shell当中都是特殊字符,如果恰好就想输入*
或者?
本身,就需要使用到脱义字符;使用脱义字符后,后面跟的特殊字符会还原成普通字符。
1 | [root@stevey ~]# ls *.txt //这里*是通配符,表示一个或多个字符,下面输出结果都匹配这个规则 |
$
变量提示符
$
是普通用户的变量提示符,root 用户是#
- 与!连用,表示上条命令的最后一个参数
~
用户家目录
对root用户来说是/root/
,普通用户是/home/username/
1 | [root@stevey test1]# su - yuanfeng |
;
适用于多条命令写在同一行,使用 ;
隔开
1 | for i in `seq 1 100` ; do echo $i; done //类似于js里面的for循环,把4条命令放在同一行书写 |
&
命令后台执行
1 | [root@stevey ~]# vmstat 1 > a.txt & |
[]
字符组合
可以是字符组合中的任意一个,也可以表示范围
;
、 &&
、 ||
三个特殊的分隔符
这三个命令都是在同一个输入两条不同命令时作为连接符使用,但是意义各有不同。假定有同一行有A、B两条command
A ; B 相当于“and”,不管A是否执行成功,都会执行B;
A && B 只有A执行成功,B才执行;否则,B不执行
A || B 相当于“or”,A执行成功则B不执行;A执行不成功则B执行,A、B两条总有一条会执行。
管道符 |
管道符的作用,一般针对文档操作比较常用,就是将前面命令的输出结果作为后面命令的输入。
常见的,比如:
cat head tail less more
:这些都是查看文档的;grep
:正则匹配工具;sort
:排序;wc
:统计,通常跟-l
选项;cut
:截取字符uniq
:检查及删除文本文件中重复出现的行列,常用参数 -c ,命令行格式:uniq-c testfile 检查文件并删除文件中重复出现的行,并在行首显示该行重复出现的次数。tee
:读取标准输入的数据,并将其内容输出给文件,类似于输出重定向,不过会同时显示出来,经常跟在管道符后面。tr
:替换或删除文件中的字符。比如,要将文本内容读取出来转换成大写字符,可以使用cat testfile |tr a-z A-Z
或者cat testfile |tr [:lower:] [:upper:]
,两者作用是一样的。split
:将一个文件分割成若干个。常见用法,比如split -n README
n 表示行数,把文件每n行为一组,拆分切割成多个以”x”开头的小文件。sed
:利用script来处理、编辑文本文件。这个比较复杂,教程在这里。awk
:同样很复杂,教程在这里。
示例:
wc
命令用来统计指定文件中的字节数、字数、行数,并将统计结果显示输出。常见参数-c
表示字节数;-l
表示行数。与wc
连用,可以实现统计的效果。
1 | [root@stevey ~]# cat /etc/passwd | wc -l //统计passwd一共有多少行 |
grep
命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
输入输出重定向
命令 | 说明 |
---|---|
command > file | 将输出重定向到 file。 |
command < file | 将输入重定向到 file。 |
command >> file | 将输出以追加的方式重定向到 file。 |
用法示例:
- 输出重定向
command1 > file
示例1:
1 | [root@stevey ~]# touch 1.txt |
示例2:
1 | [root@stevey ~]# echo 'this is a test' > 1.txt //echo 命令用于字符串的输出 |
- 追加重定向
command >> file
1 | [root@stevey ~]# pwd |
2>
错误重定向
1 | [root@stevey ~]# ls aaa 2> a.txt |
2>>
错误追加重定向
1 | [root@stevey ~]# ls aaa 2>> a.txt |
&>
重定向 相当于上述输出重定向和错误重定向的集大成者
- 输入重定向
command < file
1 | [root@stevey test]# cat 1.txt |
作业控制
指的是在shell运行当中的过程控制,主要包括:
暂停:
ctrl + Z
前台恢复:
fg
(指的是foreground)后台运行:
bg
(指的是background)撤销:
ctrl + c
(这个最常用,尤其是输错命令的时候)
练习环节:
实验了一下教材练习,有几个需要注意的点:
- 当有两个以上的任务都被暂停的时候,bash 会给暂停的任务编号。此时,输入 jobs 可查看;切换任务使用
fg n
,其中n
为任务编号。
使用&
,命令在后台运行,就会显示该任务的pid
,如果要结束任务,使用kill + pid
1 | [root@stevey ~]# vmstat 1 > a.txt & |
shell变量
变量,可以理解为通过一些比较简单的字符来替代某些具有特殊意义的设定或者数据。比如,因为有了PATH变量,查看目录的时候,只需要ls
即可。
系统环境变量都存在哪里?
系统级配置文件:
注:对系统级配置的更改会影响到所有用户;
文件名 | 特性 | 包含内容 |
---|---|---|
/etc/profile |
login shell | 该文件预置了PATH、USER、LOGNAME、MAIL、INPUTRC、HOSTNAME、HISTSIZE、umask |
/etc/bashrc |
no-login shell | 该文件预设umask,以及PS1;PS1的格式为[user@hostname dir]# user是用户名;hostname是主机名;dir是当前目录;$是一个特殊字符,root用户此处是# |
/etc/profile
与 /etc/bashrc
的区别
/etc/profile
是login shell
,通过终端输入用户名和密码进入到terminal,此时进入的shell环境就是login shell
,例如,通过ssh远程进入到主机。因此,通过login shell运行的shell命令放入到.bash_profile
中。/etc/bashrc
是no-login shell
,不需要输入用户名密码而进入的shell环境,通过gnome,KDE等桌面环境进入终端,此时进入的shell环境就是no-login shell
。因此,通过no-login shell运行的shell命令放入到.bashrc
文件中。在centos当中,’profile’系列文件的主要目的在于为登录shell设置环境变量和启动程序;而’rc’系列文件的主要目的在于设置功能和别名。
在Mac OS系统中,每次运行terminal,系统会默认运行一个login shell环境,因此mac系统配置都在
/etc/profile
和.bash_profile
这两个文件中,一般安全起见,修改当前目录下的.bash_profile
就可以了。
延伸阅读:
用户级别配置文件:
注:
用户级别的配置文件都是隐藏文件,以
.
开头,如果没有,可以新建;对这里的配置文件进行修改,只会影响当前用户。
文件名 | 包含内容 |
---|---|
.bash_profile |
定义当前用户个人华路径及环境变量的文件名称,当用户登陆时,该文件仅执行一次 |
.bashrc |
专属用户的shell的bash信息,可将别名、自定义变量写在这里,当登陆或每次打开新的shell,该文件都会被读取 |
.bash_history |
记录命令历史 |
.bash_logout |
定义用户退出时,需要执行的动作;当退出shell时,该文件会被执行 |
如何查看变量?
env
显示及设置用户变量
变量名 | 含义 |
---|---|
HOSTNAME | 主机名称 |
SHELL | 当前的shell |
HISTSIZE | 执行命令的历史记录数量,默认是1000条 |
PATH | 表示shell将到那些目录查找命令或程序 |
PWD | 当前目录 |
LANG | 与语言相关的环境变量,中文为zh_CN.UTF-8 ;english为 en_US.UTF-8 |
HOME | 当前用户家目录 |
LOGNAME | 当前用户登录名 |
set
命令 :显示及设置shell变量
包括的私有变量以及用户变量,不同类的shell有不同的私有变量 bash
,ksh
,csh
每中shell私有变量都不一样。
关于PS1
的知识
PS
,即命令提示符,也就是终端最左侧用方括号括起来的部分;
PS1 是当前用户的命令提示符,是在用户根目录下的.bash_profile中定义的。
1 | [root@stevey ~]# echo $PS1 //查看PS1 |
默认特殊符号代表的意义
特殊符号 | 含义 |
---|---|
\d |
代表日期,格式为weekday month date,例如:”Mon Aug 1” |
\H |
完整的主机名称。例如:我的机器名称为:fc4.linux,则这个名称就是fc4.linux |
\h |
仅取主机的第一个名字,如上例,则为fc4,.linux则被省略 |
\t |
显示时间为24小时格式,如:HH:MM:SS |
\T |
显示时间为12小时格式 |
\A |
显示时间为24小时格式:HH:MM |
\u |
当前用户的账号名称 |
\v |
BASH的版本信息 |
\w |
小写w,完整的工作目录名称。家目录会以 ~代替 |
\W |
大写W,利用basename取得工作目录名称,所以只会列出最后一个目录 |
\# |
下达的第几个命令 |
\$ |
提示字符,如果是root时,提示符为:# ,普通用户则为:$ |
在PS1中设置字符颜色的格式为[\e[F;Bm]
,其中F
为字体颜色,编号为30-37;B
为背景颜色,编号为40-47,具体如下:
F 字体颜色 |
B 背景颜色 |
颜色 |
---|---|---|
30 | 40 | 黑色 |
31 | 41 | 红色 |
32 | 42 | 绿色 |
33 | 43 | 黄色 |
34 | 44 | 蓝色 |
35 | 45 | 紫红色 |
36 | 46 | 青蓝色 |
37 | 47 | 白色 |
自定义命令提示符
方法一:使用export命令
1 | PS1='\[\e[37;40m\][\[\e[34;40m\]\u\[\e[37;40m\]@\h \[\e[36;40m\]\w\[\e[0m\]]\\$ ' |
方法二: 修改 /etc/bashrc
1 | vim /etc/bashrc |
方法三:自定义custom.sh
1 | cd /etc/profile.d //进入环境配置文件目录 |
echo $[变量名]
查看某个变量的值
1 | [root@stevey ~]# echo $PATH |
变量设定
关于变量设置的规则
命令行格式:export A='Alibaba'
其中,A代表变量名,'Alibaba'
代表变量内容。设置变量要符合以下规则:
变量格式 a=b , 其中a为变量名,b为变量内容,等号两边不允许有空格;
变量名只能由英、数字以及下划线组成,而且不能以数字开头;
当变量内容带有特殊字符(如空格)时,需要加上单引号;
如果变量内容中需要用到其他命令运行结果则可以使用反引号;
当变量内容含有特殊字符,需要做特殊处理,具体见下表:
变量内容 | 符号 | 示例 |
---|---|---|
特殊字符(以空格) | 使用单引号 | myname=’steve yuan’ |
变量内容本身有单引号 | 使用双引号 | mac=”steve’mac” |
变量内容需要用到其他命令 | 使用反引号(tab键上面的那个键) | hotkey=’pwd’ |
变量累加其他变量的内容 | 使用双引号 | myname=”$LOGNAME”Steve |
如何自定义变量
方法一:修改全局变量 /etc/profile
1 | vim /etc/profile //编辑此配置文件,添加变量,修改完成后按`esc` 键,输入 `:wq` 保存退出。 |
方法二:修改当前用户变量 ~/.bashrc
1 | vim ~/.bashrc //编辑此配置文件,添加变量,修改完成后按`esc` 键,输入 `:wq` 保存退出。 |
方法三:export [变量]
更改全局变量
命令行格式: export [参数][变量名称]=[变量设置值]
参数 | 描述 |
---|---|
-f |
代表[变量名称]中为函数名称。 |
-n |
删除指定的变量。变量实际上并未删除,只是不会输出到后续指令的执行环境中。 |
-p |
列出所有的shell赋予程序的环境变量。 |
- 列出当前所有的环境变量
export -p
- 定义环境变量赋值
export [变量名称]=[变量设置值]
取消变量 unset [变量名]
shell常用命令
cut命令:截取字段
命令行格式:cut [参数] [filename]
常用参数 | 含义 |
---|---|
-b | 以字节(bytes)为单位进行分割。 |
-c | 以字符(characters)为单位进行分割。 |
-d | 自定义分隔符,默认为制表符。 |
-f | 与-d一起使用,表示域(fields),指定显示哪个区域。 |
注:必须指定 -b、-c 或 -f 之一。
以字节为单位分割
-b
选项,执行此命令时,cut会先把-b
后面所有的定位进行从小到大排序,然后再提取。
who|cut -b 3-5,8
与 who|cut -b 8,3-5
一致
-b -3
表示从第一个字节到第三个字节;-b 3-
表示从第三个字节到行尾;-b -3,3-
输出整行,不会出现连续两个重叠字母。
-c
选项 以字符为单位分割
这里涉及到字符编码的扩展知识。在UTF-8编码中,英文字母、数字各占一个字节;汉字有的是3个字节(基本等同于GBK编码,约20000多个汉字),有的是4个字节(包括50000多个汉字);
通过下面这个实验,就能看出-b
和-c
选项的差别。下图中那个问号,是因为遇到多字节字符,以为一个汉字占了三个字符,所以没办法完整显示。
-nb
告诉cut不要将多字节字符拆开;这样做 -c
的效果是一样的。
-f
以域为单位分割
f表示域,后面跟数字;以域为单位时,要同时使用 -d
后面跟分隔符,用单引号括起来。命令行格式为:cut -d [分隔符] -f n [filename]
- 以空格为单位,分割显示a.txt
- 与管道符连用。例如,查看
passwd
第一列的内容
sort 命令: 排序
命令行格式:sort [参数] [filename]
常用参数 | 用法 |
---|---|
-t | 后面跟分隔符,跟cut命令-d选项作用一样。 |
-n | 按照纯数字排序,字母和特殊符号视为0 |
-r | reverse ,反向排序 |
-u | 去掉重复项 |
-k | 按照某一列的顺序进行排序 |
排序的优先级规则:
除非指定-r
参数,否则按照一下优先级顺序
以数字开头的行优先级最高;
以小写字母开头的行优先级次之;
待排序内容按字典序进行排序;
注:sort命令只做排序,并不会改动文件本身;如果需要排序后生成新的文件,可以采取输出重定向。
示例:
- 文件内容进行排序,默认按照字母顺序进行排序
1 | [root@stevey ~]# head -n 5 /etc/passwd | cut -d ':' -f 1 > a.txt //准备实验文件,passwd这个文件比较长,所以只取第一列、前5行的内容,重定向到a.txt |
- sort还可以同时对多个文件进行排序
sort [file1] [file2]
1 | [root@stevey ~]# tail -n 5 /etc/passwd | cut -d ':' -f 1 > b.txt |
-r
参数,进行反向排序
1 | [root@stevey ~]# sort -r a.txt |
-k
按照某一列进行排序,比如下面对第9列进行排序 注意此处,如果跟n参数连用的话,k放在后面跟着数字,否则会报错
-n
使用纯数字排序,下面安装第5列的数字升序排列 注:字母和特殊符号被视为0
wc
统计
命令行格式: wc [参数] [filename]
常用参数 | 用法 |
---|---|
-l | 统计行数 |
-m | 统计字符数,包括换行符$ |
-L | 大写L,统计字符数,不包括换行符$ |
-w | 统计词数 |
示例
1 | [root@stevey ~]# wc -l a.txt //统计行数 |
wc
还可以跟管道符连用,可以实现很多奇妙的效果
1 | [root@stevey ~]# cat /etc/passwd | wc -l //统计一共有多少密码 |
uniq
删除重复行并显示
注意:
使用uniq前,要先用sort 进行排序,否则不起作用;
uniq 常用参数
-c
表示统计重复的行数;uniq并不会真的删除重复项,如果确实需要删除的话,应输出重定向;
示例:
tee
类似输出重定向
读取标准输入的数据,并将其内容输出给文件,跟输出重定向相似,不过该命令会把输出内容显示出来。
tr
替换或删除文件中的字符
常用参数 | 用法 |
---|---|
-d | 删除某个字符,后面跟需要删除的字符 |
-s | 删除重复的字符 |
示例:
-d
删除特定字符 注:这个也不是真正的删除文件,只是看起来删除了。
1 | head -n 5 /etc/passwd | cut -d ':' -f 1 > a.txt |
cat testfile |tr a-z A-Z
或者cat testfile |tr [:lower:] [:upper:]
,两者作用是一样的。
-s
或--squeeze-repeats
:把连续重复的字符以单独一个字符表示;
1 | echo "thissss is a text linnnnnnne." | tr -s ' sn' |
split
切割文档
命令行格式:split [参数] [待切割文件] [切割生产文件]
常用参数 | 用法 |
---|---|
-b | 按照文件大小切割,单位为字节bytes |
-l | 按照行数切割 |
-b
按照大小切割
如果不指定目标文件名,这会以xaa、xab、xac……这样的格式名来自动保存生成文件。
1 | [root@stevey test1]# ls |
指定文件名的命令