前言
什么是shell脚本呢?shell脚本就是利用shell的功能所写的一个纯文本的程序,将一些shell的语法和命令写在里面,搭配正则表达式,管道命令,数据流重定向等功能,达到我们所想要的处理结果。
简单的说,就是讲很多命令写在一起,让用户一下可以处理复杂的操作。(执行一个shell script,就能够一次执行很多条命令)
变量
变量是shell脚本中的一个重要角色,当然学习其他任何语言都会接触到变量这个词。shell脚本中的变量不需要声明类型,直接只用变量名=变量值
即可声明一个变量。
- 变量的分类可以分为如下四种:
- 局部变量
定义在脚本内的,只能在当前脚本中使用。例如:name=longlongago
其中name是变量名,longlongago是变量的值,中间用=连接,=号的两边不能留空格。 - 环境变量
可以在任意一个脚本中使用的变量,称为环境变量,例如常见的PATH。可以通过env命令查看当前的环境变量:
[root@iZxvryruh5alhlZ ~]# env
XDG_SESSION_ID=215
HOSTNAME=iZxvryruh5alhlZ
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_TTY=/dev/pts/1
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/root
PATH=/data/mysql/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin
PWD=/root
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
LOGNAME=root
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/env
那么如何声明一个环境变量呢?很简单,通过export既可以将一个局部变量声明为环境变量,例如:
[root@iZxvryruh5alhlZ ~]# name=longlongago
[root@iZxvryruh5alhlZ ~]# export name
此时再次运行env命令可以看到多了一个name变量。
- 参数变量
参数变量也称位置变量,专门为了表示一个脚本传递的参数信息,如下:
#执行一个脚本install.sh,具有三个参数faster、higher、stronger
sh install.sh faster higher stronger
#其中:
#$0:脚本本身的名字,即install
#$1:脚本传入的第一个参数,即faster
#$2:脚本传入的第一个参数,即higher
#$3:脚本传入的第一个参数,即stronger
- shell变量
就是每个shell脚本都具备的命令,用来表示一定的功能,具体看下表所示:
命令 | 含义 |
---|---|
$# | 传递给脚本的参数个数 |
$@ | 显示所有参数 |
$* | 与$*相同 但每个参数都加上了引号' |
$$ | 当前进程ID |
$! | 后台运行的最后进程ID |
$. | 同set |
$? | 显示最后命令的退出状态,0表示没有错误 |
- 变量的使用
- 使用$符号跟变量名,如
echo $name
- 双引号和单引号的区别:
双引号""中的内容如果包含$变量名
,那么会引用变量,例如:
name=longlongago
echo "my name is $name"
#输出结果:my name is longlongago
单引号''中的内容不会引用变量,是什么就显示什么,例如:
name=longlongago
echo 'my name is $name'
#输出结果:my name is $name
数据流重定向
什么是数据流重定向呢?比如说我们执行一个命令,这个命令会读取一个文件的数据,然后再将数据显示到屏幕上或者某个文件中。举一个栗子:
#将根目录下的目录和文件夹输出到/data/rootfile文件中
ll / > /data/rootfile
#标准输出,使用 >或>>,>表示覆盖,>>表示追加
#标准错误输出,使用 2>或2>>,2>表示覆盖,2>>表示追加
如果要将错误信息忽略掉而不显示或存储呢?这个时候黑洞设备/dev/null就很重要了,这个/dev/null可以吃掉任何导向它的消息被忽略。例如:
id ccc 2>/dev/null
#由于ccc用户不存在,则命令运行后会将错误信息发到/dev/null设备,从而被忽略。
管道命令
如果有一群数据必须经过多个步骤处理,最后形成我们需要的参数或者变量。管道命令使用的是"|",主要是将前一个命令的standout做为后一个standin来完成高难度操作。
栗子:
#查询最后登陆的账户信息,并且用空格分隔,剪接出第一列账户名
last | cut -d ' ' -f 1
逻辑判断
逻辑判断命令有&&和||两种,命令的具体说明我们来看一下如下的表格:
命令执行情况 | 说明 |
---|---|
cmd1 && cmd2 | 若cmd1执行完毕且正确($? = 0),则执行cmd2; 若cmd1执行完毕且为错误($? != 0),则cmd2不执行。 |
cmd1 || cmd2 | 若cmd1执行完毕且正确($? = 0),则cmd2不执行; 若cmd1执行完毕且为错误($? != 0),则执行cmd2。 |
举个栗子:
#用户组cxl不存在,则添加用户组cxl
[ -z "$(grep 'cxl' /etc/group)" ] && groupadd cxl
#若用户cxl不存在,则添加用户cxl
id cxl || useradd cxl
条件判断
1. if...then
语法:
if [ 条件判断式 ];then
#这里写:当条件成立时,需要执行的命令
fi
语法还是比较简单的,需要注意的是:方括号[]与中间的条件判断式必须有一个空格。条件判断式可以有很多种,包括了对整数的判断、文件的判断、字符串的判断、多重条件判断等。
- 数值判断所用到的语法如下:
判断标志 | 代表含义 |
---|---|
-eq | 相等 |
-ne | 不相等 |
-gt | 大于 |
-ge | 大于等于 |
-lt | 小于 |
-le | 小于等于 |
- 文件判断的语法:
判断标志 | 代表含义 |
---|---|
-e | 该文件名是否存在 |
-f | 该文件名是否存在,且是一个文件 |
-d | 该文件名是否存在,且是一个目录 |
-r | 该文件名是否存在,且可读 |
-w | 该文件名是否存在,且可写 |
-x | 该文件名是否存在,且可执行 |
*字符串的判断
判断标志 | 代表含义 |
---|---|
-z | 字符串是否为空 |
-n | 字符串是否为非空 |
= | 字符串是否相等 |
!= | 字符串是否不相等 |
- 多重条件判断
判断标志 | 代表含义 |
---|---|
-a | 两个条件同时成立!即:并且 |
-o | 两个条件之一成立!即:或者 |
! | 反向状态 |
2.case...in...
语法:
case $变量名 in
"第一个变量内容")
#成立时,需要执行的内容
;;
"第二个变量内容")
#成立时,需要执行的内容
;;
*)#这里*表示除了第一和第二种的其他所有情况
exit 1
;;
esac
循环
1. while do done
语法:
while [ 条件判断式 ]
do
#程序块
done
表示当条件成立时执行do后面的内容。
2. until do done
语法:
until [ 条件判断式 ]
do
#程序块
done
表示当条件成立时停止执行do后面的内容。
3. for do done
语法:
for var in '一个数列'
do
#程序块
done
遍历数列中所有的元素,执行程序块中的内容。
函数
function
shell的执行顺序是自上而下,从左往右,因此shell中的方法一定要放在前面。
- function的语法:
function fname() {
程序段
}
- function的使用:
function的使用,直接用函数的名字就可以了,但是如何传递参数呢?这其实跟shell脚本的参数变量一样,$0
表示当前方法名,$1、$2、$3
等表示当前方法的第一、二、三个三处,如下
fname zhaoqian sunli zhouwu
其中fname表示函数名,zhaoqian、sunli、zhouwu分别代码第一、二、三个参数。