04.17 Shell高级编程
第一章 Shell环境变量
1. 什么是变量
变量就是用一个固定的字符串(也可能是字符数字等的组合),替代更多更复杂的内容,这个内容里可能还会包含变量和路径,字符串等其他内容。变量的定义是存在内存中。
x=1
y=2
2. 变量类型
a)环境变量/全局变量
可以在创建他们的Shell及其派生出来的字Shell中使用。环境变量又可以分为自定义环境变量和bash内置的环境变量。
b) 局部变量/普通变量
只能在创建他们的Shell函数或Shell脚本中使用,我们创建的一般是普通变量。
3. 和变量相关的配置文件
[aaa@qq.com-downtime scripts]# ll /etc/profile /etc/bashrc ~/.bashrc ~/.bash_profile /etc/profile.d/
-rw-r--r-- 1 root root 2730 Apr 16 14:23 /etc/bashrc
-rw-r--r-- 1 root root 1860 Mar 28 22:36 /etc/profile
-rw-r--r--. 1 root root 176 May 20 2009 /root/.bash_profile
-rw-r--r--. 1 root root 176 Sep 23 2004 /root/.bashrc
4. 设置全局变量(环境变量)的方法
(1)变量名大写
(2)使用export定义
(3)全局生效放在/etc/bashrc
(4)局部生效放在~/.bashrc
5. 变量文件开机启动顺序
6. 位置变量
$0获取当前执行的shell脚本的文件名,如果执行脚本带路径那么就包括脚本路径。
condrestart|try-restart)
rh_status_q || exit 0
restart
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
exit 2
esac
exit $?
$n 获取当前执行的shell脚本的第n个参数值,n=1..9,当n为0时表示脚本的文件名,如果n大于9用大括号括起来{10},参数以空格隔开。
$# 获取当前执行的shell脚本后面接的参数的总个数。
7. 进程状态变量
$? 获取执行上一个指令的返回值(0位成功,非0为失败)
返回值 | 含义 |
---|---|
0 | 表示运行成功 |
2 | 权限拒绝 |
1~125 | 表示运行失败,脚本命令、系统命令错误或参数传递错误 |
126 | 找到该命令,但无法执行 |
127 | 未找到要运行的命令 |
>128 | 命令被系统强制结束 |
第二章 变量的数值运算
运算 | 含义 |
---|---|
++ – | 增加及减少,可前置也可放结尾 |
+ - ! ~ | 一元的正好与符号,非,逻辑与位的取反 |
* / % | 乘法、除法、取余 |
< <= > >= | 比较符号 |
== != | 相等、不相等 |
<< >> | 向左位移,向右位移 |
& | 位的AND |
^ | 位的异 |
| | 位的或 |
&& | 位的AND |
|| | 位的OR |
?: | 条件表达式 |
= += -= *= /= %= &= ^= <<= >>= |= | 赋值运算符 |
** | 幂运算 |
[root@CentOS7 ~]# ((a=1+2**3-4%3))
[root@CentOS7 ~]# echo $a
8
[root@CentOS7 ~]# b=$((1+2**3-4%3))
[root@CentOS7 ~]# echo $b
8
[root@CentOS7 ~]# echo $((1+2**3-4%3))
8
1. 【$(())】
同$(())
[root@Never-downtime tmp]# echo $[2+3]
5
[root@Never-downtime tmp]# echo $[2*3]
6
2. 数值判断
[root@CentOS7 ~]# echo $((4>2))
1
[root@CentOS7 ~]# echo $((4<2))
0
第三章 read读入
1. 功能说明
Read lines from a file into an array variable
read命令从标准输入中读取一行,并把输入行的每个字段的值指定给shell变量。
2. 选项参数
-p prompt 设置提示信息
-t timeout 设置输入超时时间,单位s。
[root@CentOS7 ~]# read -p "qing shu ru yige zhi:" a
qing shu ru yige zhi:3
[root@CentOS7 ~]# echo $a
3
3. 清楚赋值变量unset
[root@CentOS7 ~]# unset a
[root@CentOS7 ~]# echo $a
4. 实现一个加减乘除的计算器
[aaa@qq.com scripts]# vi read2.sh
#!/bin/bash
read -p "请输入2个值:" a b
echo "$a+$b=$(($a+$b))"
echo "$a-$b=$(($a-$b))"
echo "$a*$b=$(($a*$b))"
echo "$a/$b=$(($a/$b))"
[aaa@qq.com scripts]# sh read2.sh
请输入2个值:6 2
6+2=8
6-2=4
6*2=12
6/2=3
[aaa@qq.com scripts]# sh read2.sh
请输入2个值:2 8
2+8=10
2-8=-6
2*8=16
2/8=0
第四章 测试表达式
1. 常用文件测试操作符号
常用文件测试操作符号 | 说明 |
---|---|
-f 文件,英文file | 文件存在且为普通文件则真,即测试表达式成立。 |
-d文件,英文directory | 文件存在且为目录文件则真,即测试表达式成立。 |
-s文件,英文size | 文件存在且为文件大小不为0则真,即测试表达式成立。 |
-e文件,英文exist | 文件存在则真,即测试表达式成立,只要有文件就行,区别-f |
-r文件,英文read | 文件存在且可读则真,即测试表达式成立。 |
-w文件,英文write | 文件存在且可写则真,即测试表达式成立。 |
-x文件,英文executable | 文件存在且可执行则真,即测试表达式成立。 |
-L文件,英文link | 文件存在且为链接文件则真,即测试表达式成立。 |
f1 -nt f2,英文newer than | 文件f1比文件f2新则真,即测试表达式成立,根据文件修改时间计算。 |
f1 -ot f2,英文older than | 文件f1比文件f2旧则真,即测试表达式成立,根据文件修改时间计算。 |
2. 字符串测试操作符
字符串测试操作符的作用:比较两个字符串是否相同、字符串长度是否为零,字符串是否为NULL。Bash区分零长度字符串和空字符串。
常用字符串测试操作符 | 说明 |
---|---|
-z “字符串” | 若串长度为0则真,-z理解为zero |
-n “字符串” | 若串长度不为0则真,-n理解为no zero |
“串1” = “串2” | 若串1等于串2则真,可以使用”==”代替”=” |
“串1” != “串2” | 若串1不等于串2则真,但不能使用”!==”代替”!=” |
特别注意,以上表格中的字符串测试操作符号务必要用”“引起来。[-z “$string”]字符串比较,比较符号两端最好有空格,参考系统脚本。
[ “$password” = “john” ]中[ “$password” = “john” ]之间必须存在空格。
引号可以不加,遇到空格必须加,但是推荐使用引号!
3. 整错错误示例
正确 | 中括号、引号、空格 | [ “abc” = “abc” ] && echo “eq” |
错误 | 中括号、引号 | [ “abc”=”ac” ] && echo “eq” |
错误 | 中括号 | [ abc=bc ] && echo “eq” |
4. 整数二元比较操作符
在[]中使用的比较符 | 说明 |
---|---|
-eq | equal等于 |
-ne | not equal大等于 |
-gt | greater than 大于 |
-ge | greater equal 大于等于 |
-lt | less than 小于 |
-le | less equal 小于等于 |
5. 逻辑操作符
在[]中使用的逻辑操作符 | 说明 |
---|---|
-a | 与and,两端都为真则真 |
-o | 或or,有一个真就真 |
! | 非not,相反则为真 |
小结:多个[]之间的逻辑操作符是&&或||,&&前面成功执行后面,||前面不成功执行后面。
综合实战案例:开发shell脚本分别实现以脚本传参以及read读入的方式比较2个整数大小。用条件表达式(禁止if)进行判断并以屏幕输出的方式提醒用户比较结果。注意:一共是开发2个脚本。当用脚本传参以及read读入的方式需要对变量是否为数字、并且传参个数不对给予提示。
#!/bin/bash
a=$1
b=$2
[ "$#" -ne 2 ] && echo "警告:这里必须输入两个字符" && exit 1
zimu1=`echo $1|sed 's#[0-9]##g'`
zimu2=`echo $2|sed 's#[0-9]##g'`
[ -n "${zimu1}" ] && echo "警告:第一个字符类型必须是数字" && exit 2
[ -n "${zimu2}" ] && echo "警告:第二个字符类型必须是数字" && exit 2
[ $a -eq $b ] && echo "$a = $b"
[ $a -gt $b ] && echo "$a > $b"
[ $a -lt $b ] && echo "$a < $b"
read读入
read -t 5 -p "提示:请输入2个字符" a b
[ -z "$a" -o -z "$b" ] && echo "必须是两个字数" && exit 1
replace1=$(echo $a |sed "s#[0-9]##g")
replace2=$(echo $b |sed "s#[0-9]##g")
[ -n "$replace1" ] && echo "警告:第一个字符类型必须是数字" && exit 2
[ -n "$replace2" ] && echo "警告:第二个字符类型必须是数字" && exit 2
[ "$a" -eq "$b" ] && echo "$a = $b" && exit
[ "$a" -gt "$b" ] && echo "$a > $b" && exit
[ "$a" -lt "$b" ] && echo "$a < $b" && exit
第五章 if条件语句
1. if单分支条件句语
if [条件]
then
指令
if
或
if [条件];then
指令
fi
提示:分号相当于命令换行,上面两种语法等同。
特殊写法if [ -f "$file" ];then echo 1 ;fi 相当于[ -f "$file" ] && echo 1
[aaa@qq.com scripts]# vi size_Comparison1.sh
#!/bin/bash
a=$1
b=$2
if [ "$#" -ne "2" ]
then
echo "警告:这里必须输入两个字符" && exit 1
fi
replace1=$(echo $1 |sed "s#[0-9]##g")
replace2=$(echo $2 |sed "s#[0-9]##g")
if [ -n "$replace1" ]
then
echo "警告:第一个字符类型必须是数字" && exit 2
fi
if [ -n "$replace2" ]
then
echo "警告:第二个字符类型必须是数字" && exit 2
fi
if [ "$a" -eq "$b" ]
then
echo "$a = $b"
fi
if [ "$a" -gt "$b" ]
then
echo "$a > $b"
fi
if [ "$a" -lt "$b" ]
then
echo "$a < $b"
fi
2. if双分支条件语句
if [ 条件 ]
then
指令1
else
指令2
fi
3. 判断是否为文件
[aaa@qq.com scripts]# vi iftuo.sh
#!/bin/bash
if [ -f "read1.sh" ]
then
echo 0
else
echo 1
fi
相当于[ -f "read1.sh" ] && echo 0 || echo 1
4. if多分支语句
if [ 条件1 ]
then
指令1
elif [ 条件2 ]
then
指令2
elif [ 条件3 ]
then
指令3
elif [ 条件4 ]
then
指令4
....
else
指令n
fi
5. 判断两个数字的大小
23 if [ "$a" -eq "$b" ]
24 then
25 echo "$a=$b"
26
27 elif [ "$a" -gt "$b" ]
28 then
29 echo "$a>$b"
30
31 else [ "$a" -lt "$b" ]
32 echo "$a<$b"
33 fi
6. if语句总结
分支 | 语法 | 结果 |
---|---|---|
单分支 | if then fi | 一个条件一个结果 |
双分支 | if then else fi | 一个条件两个结果 |
多分支 | if then elif elif else fi | 多个条件多个结果 |
第六章 for循环结构语法
for 变量名 in 变量取值列表
do
指令.....
done
1. 示例循环10次
[root@Never-downtime scripts]# for i in {00..10}
> do
> echo $i
> done
00
01
02
03
04
05
06
07
08
09
10
[root@Never-downtime scripts]# for i in {00..10}; do echo $i; done
2. 小结
in后面的字符个数控制循环的次数
将i后面的字符分别赋值给变量i,在do后面可以引用变量i也可以不用
以空格区分,[root@oldboyedu-35 data]# for i in {1..10};do useradd test$i;done
第七章 获取随机数的几种方法
1. 通过系统变量$RANDON
[root@CentOS7 ~]# echo $RANDOM
9820
[root@CentOS7 ~]# echo $RANDOM
1468
[root@CentOS7 ~]# echo $RANDOM
14955
2. 通过openssl产生
[root@CentOS7 ~]# openssl rand -base64 8|md5sum
b025e02d40e910f8a9cd36f98ff363d7 -
[root@CentOS7 ~]# openssl rand -base64 8|md5sum
6a9619eab8009f0ca5f56a82475c2077 -
3. echo $(date +%N)
[root@CentOS7 ~]# echo $(date +%N)
216956783
[root@CentOS7 ~]# echo $(date +%N)
349010758
[root@CentOS7 ~]# echo $(date +%N)
773229182
4. urandom
[root@CentOS7 ~]# head /dev/urandom |cksum
3017719303 1809
[root@CentOS7 ~]# head /dev/urandom |cksum
1901402952 1933
[root@CentOS7 ~]# head /dev/urandom |cksum
3354308804 2453
5. uuidgen码有硬件、时间、机器当前运行信息等组成,理论上在互联网中唯一
[aaa@qq.com ~]# uuidgen
93841c31-0664-462d-8a28-a406b3791bb0
[aaa@qq.com ~]# uuidgen
bfb2487f-5cbd-4daa-b847-9870920a706c
[aaa@qq.com ~]# uuidgen
cce1d3c9-041a-4cd8-a3a0-1b399fee4c51
第八章 case结构条件句语法
case “字符串标量” in
值1)
指令1
;;
值2)
指令1
;;
*)
指令
esac
#注:case语句相当于一个if的多分支结构语句
1. case语句小结
case语句就相当于多分支的if语句。case语句的优势是更规范、易读。
case语句适合变量的值少,且为固定的数字或字符串集合。(1,2,3)或(start,stop,restart)。
系统服务启动脚本传参的判断多用case语句,多参考rpcbind/nfs/crond脚本。
结合示例:打印选择菜单,按照选择一键安装不同的web服务。
shmenu.sh
1.[install lamp]
2.[install lnmp]
3.[exit]
pls input the num you want:
要求:
1、当用户输入1时,输出“startinstalling lamp提示”。然后执行/servsr/scripts/lamp.sh。脚本内容输出“lampis installed”后退出脚本, lamp一键安装脚本。
2、当用户输入2时,输出“startinstalling lnmp提示”,然后执行/server/scripts/lnmp.sh。脚本内容输出“lnmpis installed”后退出脚本, lnmp一键安装脚本。
3、当输入3时,退出当前菜单及脚本。
4、当输入任何其它字符,给出提示“Input error”后退出脚本。
5、要对执行的脚本进行相关的条件判断,例如:脚本文件是否存在,是否可执行等判断,尽量用上前面讲解的知识点。
[aaa@qq.com scripts]# vi case.sh
#!/bin/bash
cat<<EOP
本程序支持安装的服务:
1.安装LAMP服务
2.安装LNMP服务
3.exit 退出安装
EOP
read -p "请输入你的选择:" a
case $a in
1)
echo "startinstalling lamp"
lampScripts=/server/scripts/lamp.sh
[ -f $lampScripts ] && sh $lampScripts || exit 2
;;
2)
echo "startinstalling lnmp"
lnmpScripts=/server/scripts/lnmp.sh
[ -f $lnmpScripts ] && sh $lnmpScripts || exit 3
;;
3)
exit
;;
*)
echo "您的输入有误,请重新输入"
;;
esac
第九章 Linux色值 彩色字体值
echo -e "\033[30m 黑色字oldboy trainning \033[0m"
echo -e "\033[31m 红色字oldboy trainning \033[0m"
echo -e "\033[32m 绿色字oldboy trainning \033[0m"
echo -e "\033[33m 黄色字oldboy trainning \033[0m"
echo -e "\033[34m 蓝色字oldboy trainning \033[0m"
echo -e "\033[35m 紫色字oldboy trainning \033[0m"
echo -e "\033[36m 天蓝字oldboy trainning \033[0m"
echo -e "\033[37m 白色字oldboy trainning \033[0m"
第十章 Linux色值 彩底白字值
echo -e "\033[40;37m 黑底白字 welcome to old1boy\033[0m"
echo -e "\033[41;37m 红底白字 welcome to old2boy\033[0m"
echo -e "\033[42;37m 绿底白字 welcome to old3boy\033[0m"
echo -e "\033[43;37m 黄底白字 welcome to old4boy\033[0m"
echo -e "\033[44;37m 蓝底白字 welcome to old5boy\033[0m"
echo -e "\033[45;37m 紫底白字 welcome to old6boy\033[0m"
echo -e "\033[46;37m 天蓝白字 welcome to old7boy\033[0m"
echo -e "\033[47;30m 白底黑字 welcome to old8boy\033[0m"
第十一章 while条件句
while 条件
do
指令
done
[aaa@qq.com ~]# vi while.sh
#!/bin/bash
while true
do
uptime >>/tmp/uptime.log
sleep 1
done
[aaa@qq.com ~]# tailf /tmp/uptime.log
09:29:04 up 2:00, 4 users, load average: 0.00, 0.01, 0.04
09:29:06 up 2:00, 4 users, load average: 0.00, 0.01, 0.04
09:29:08 up 2:00, 4 users, load average: 0.00, 0.01, 0.04
09:29:10 up 2:00, 4 users, load average: 0.00, 0.01, 0.04
第十二章 各种语句小结
1. while循环
while循环的特长是执行守护进程以及我们希望循环不退出持续执行,用于频率小于1分钟循环处理(crond),其他的while循环几乎都可以被for循环替代。
2. case语句
case语句可以被if语句替换,一般在系统启动脚本传入少量固定规则字符串用case语句,其他普通判断多用if。
3. until循环
until执行死循环,表达式成立后结束循环。
until [ $# -eq 0 ]
do
echo $*
shift
done
1 2 3 4 5
2 3 4 5
3 4 5
4 5
5
第十三章 循环控制语句
continue 跳过当次循环
break 跳过整个循环
exit 退出脚本
return 退出函数
1. break
break脚本:
[aaa@qq.com scripts]# vi break.sh
#!/bin/bash
for a in {01..10}
do
if [ $a -eq 5 ]
then
break
else
echo $a
fi
done
echo "我猜你现在在看这几行字..."
输出结果:
[aaa@qq.com scripts]# sh break.sh
01
02
03
04
我猜你现在在看这几行字...
2. exit
exit脚本:
#!/bin/bash
for a in {01..10}
do
if [ $a -eq 5 ]
then
exit
else
echo $a
fi
done
echo "我猜你现在在看这几行字..."
输出结果:
[root@Never-downtime scripts]# sh break.sh
01
02
03
04
3. continue
continue脚本:
#!/bin/bash
for a in {01..10}
do
if [ $a -eq 5 ]
then
continue
else
echo $a
fi
done
echo "我猜你现在在看这几行字..."
输出内容:
[aaa@qq.com scripts]# sh break.sh
01
02
03
04
06
07
08
09
10
我猜你现在在看这几行字...