欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

04.17 Shell高级编程

程序员文章站 2022-05-09 17:20:53
...

第一章 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. 变量文件开机启动顺序
04.17 Shell高级编程

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
指令
ifif  [条件];then
指令
fi
提示:分号相当于命令换行,上面两种语法等同。

特殊写法if [ -f "$file" ];then echo 1fi 相当于[ -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 “字符串标量” in1)
       指令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
我猜你现在在看这几行字...