Shell
为什么要学习 shell 编程
- Linux/Unix 系统的底层及基础应用软件的核心大都涉及 Shell 脚本的内容。
- 减少重复性工作,提升运维人员的工作效率。
- Shell 脚本是企业中 Linux 自动化运维必备不可替代的工具。
学好 shell 编程所需 Linux 基础
- 熟练掌握 VIM。
- 对 Linux 系统常用命令的掌握程度就直接决定运维人员 Shell 脚本编程的掌握高度。
- 正则表达式及三剑客(grep、sed、awk)。
如何才能学好 shell 编程
- 变量基础、条件表达式、if 判断、for 循环、While 循环、case 语句、循环控制命令
- 初学者,一定要从简单做起,最小化代码学习,复杂的程序都是由许多小的功能模块组合而成的。
- 多模仿、多练习、多思考。
- 锻炼编程思维:将需求理解透彻,然后把大的需求进行分解,逐步形成小的程序或模块。
什么是 shell
shell 是一个命令解释器,它的作用是解释执行用户输入的命令及程序等,用户输入一条命令,Shell 就解释执行一条。这种从键盘输入命令,就可以立即得到回应的对话方式,被称之为交互的方式。
shell 存在于操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕返回给用户,当我们输入系统用户名和密码,登录到 Linux 后的所有操作都是由 Shell 解释并执行的。
针对命令解释器 shell 在操作系统中所处的位置给了基本图解。
常用操作系统的默认 shell
操作系统 | 默认使用的 shell |
---|---|
Linux | bash(Bourne Again shell) |
Solaris、FreeBSD | sh(Bourne shell) |
AIX | ksh(Korn Shell) |
通过以下两种方法可查看 CentOS Linux 系统默认的 shell
1# 方法一
2[root@localhost ~]# echo $SHELL
3/bin/bash
4
5# 方法二
6[root@localhost ~]# grep ^root /etc/passwd
7root❌0:0:root:/root:/bin/bash
shell 脚本的创建与执行
1[root@localhost software]# cat test.sh
2#!/bin/bash
3echo "This is a test!"
一个规范的 shell 脚本在第一行会指出由哪个程序(解释器)来执行脚本中的内容,这一行内容在 Linux bash 变成中一般为:
1#!/bin/bash
“#!”的作用:在执行 bash 脚本的时候,内容会根据 #! 后的解释器来确定该用哪个程序解释这个脚本中的内容。
执行方式
1[root@localhost software]# bash test.sh
2This is a test!
变量
变量是暂时存储数据的空间及其引用,所存储的数据存在于内容空间中,通过正确地引用内存空间中变量的名字就可以取出变量对应的数据。
变量分为:普通变量(局部变量)、环境变量(全局变量)
普通变量
普通变量也称为局部变量,只能在创建他们的 shell 函数或 shell 脚本中使用。
1# 定义变量
2[root@localhost software]# dog="My name is lion"
3[root@localhost software]# echo $dog
4My name is lion
5
6# 取消变量
7[root@localhost software]# unset dog
8[root@localhost software]# echo $dog
局部变量定义及赋值的规则:
- 变量内容有空格且希望解析内容中的变量,使用双引号
1[root@localhost ~]# a="My name is $USER" 2[root@localhost ~]# echo $a 3My name is root
- 希望原样输出变量的内容时使用单引号
1[root@localhost ~]# a='My name is $USER' 2[root@localhost ~]# echo $a 3My name is $USER
- 要使用反引号将赋值的命令括起来,或者用 $()
1[root@localhost ~]# a="today is `date`" 2[root@localhost ~]# echo $a 3today is Sat Jun 5 10:57:40 CST 2021
环境变量
环境变量也可称为全局变量,可以在创建他们的 shell 及其派生出来的任意子进程 shell 中使用,环境变量又可分为自定义环境变量和 bash 内置环境变量。
1# bash内置环境变量
2[root@localhost software]# echo $USER
3root
4[root@localhost software]# echo $SHELL
5/bin/bash
6[root@localhost software]# echo $HOME
7/root
8
9# 自定义环境变量
10[root@localhost software]# export test=1
11[root@localhost software]# echo $test
121
13
14# 环境变量永久生效(优先级)
15/etc/bashrc >
16~/.bashrc >
17~/.bash_profile >
18/etc/profile
19
20export TMOUT=30000
显示当前环境变量名称及对应值
1[root@localhost ~]# env
位置特殊参数变量
位置变量 | 作用说明 |
---|---|
$0 | 获取当前执行 shell 脚本的文件名,如果执行脚本带路径,那么就包括脚本路径 |
$n | 获取当前执行的 shell 脚本的第 n 个参数值,n=1..9,如果 n 大于 9,则用大括号括起来,例如 ${10},接的参数以空格隔开 |
$* | 获取当前 shell 脚本所有传参的参数 |
$# | 参数的个数 |
1[root@localhost script]# cat test.sh
2echo $0
3echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
4echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
5echo $*
6echo $#
7
8[root@localhost script]# bash test.sh {a..z}
9test.sh
10a b c d e f g h i a0 a1 a2 a3 a4 a5
11a b c d e f g h i j k l m n o
12a b c d e f g h i j k l m n o p q r s t u v w x y z
1326
14
15# 关于$#的用法
16[root@localhost script]# cat network.sh
17if [ "$#" -eq 0 ]
18then
19 echo "Usage: ${0} {start|stop|restart}"
20fi
21echo $1
进程特殊状态变量
进程变量 | 作用说明 |
---|---|
$? | 获取执行上一个指令的执行状态返回值,0 为成功,非零为失败 |
$$ | 获取当前执行的 shell 脚本的进程号(PID), |
1# $? 的用法
2[root@localhost script]# ls
3network.sh test.sh
4[root@localhost script]# echo $?
50
6[root@localhost script]# l
7-bash: l: command not found
8[root@localhost script]# echo $?
9127
10
11# $$ 的用法
12[root@localhost script]# echo $$
1314615
字符串处理
1# 计算字符串长度
2[root@localhost ~]# var1="I love you,Do you love me"
3[root@localhost ~]# echo ${#var1}
425
5[root@localhost ~]# expr length "$var1"
625
7
8# 获取字符索引位置
9[root@localhost ~]# var1="quickstart is a app"
10[root@localhost ~]# expr index "$var1" start
116
12[root@localhost ~]# expr index "$var1" uniq
131
14[root@localhost ~]# var1="qkuickstart is a app"
15[root@localhost ~]# expr index "$var1" cnk
162
17
18# 获取子串长度
19[root@localhost ~]# expr match "$var1" .*app
2019
21[root@localhost ~]# expr match "$var1" quickstart
2210
23
24# 抽取字符串中的子串 expr索引是从1开始计算, postion索引是从0开始计算
25[root@localhost ~]# var1="kafka hadoop yarn mapreduce"
26[root@localhost ~]# echo ${var1:10}
27op yarn mapreduce
28[root@localhost ~]# echo ${var1:5:10}
29hadoop ya
30[root@localhost ~]# echo ${var1: -5}
31educe
32[root@localhost ~]# echo ${var1: -5:2}
33ed
34[root@localhost ~]# expr substr "$var1" 5 10
35a hadoop y
变量替换
1[root@localhost ~]# var1="I love you,Do you love me"
2[root@localhost ~]# echo $var1
3I love you,Do you love me
4
5# 从头开始匹配,最短删除
6[root@localhost ~]# v1=${var1#*ov}
7[root@localhost ~]# echo $v1
8e you,Do you love me
9# 从头开始匹配,最长删除
10[root@localhost ~]# v2=${var1##*ov}
11[root@localhost ~]# echo $v2
12e me
13
14# 从尾部开始删除,最短匹配
15[root@localhost ~]# v3=${var1%ov*}
16[root@localhost ~]# echo $v3
17I love you,Do you l
18# 从尾部开始删除,最长匹配
19[root@localhost ~]# v4=${var1%%ov*}
20[root@localhost ~]# echo $v4
21I l
22
23# 替换变量内的旧字符串为新字符串,只替换一次
24[root@localhost ~]# echo $PATH
25/application/mysql/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
26[root@localhost ~]# v5=${PATH/bin/BIN}
27[root@localhost ~]# echo $v5
28/application/mysql/BIN:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
29
30# 替换变量内的旧字符串为新字符串,替换全部
31[root@localhost ~]# echo $PATH
32/application/mysql/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
33[root@localhost ~]# v6=${PATH//bin/BIN}
34[root@localhost ~]# echo $v6
35/application/mysql/BIN:/usr/local/sBIN:/usr/local/BIN:/usr/sBIN:/usr/BIN:/root/BIN
综合练习脚本
1[root@localhost software]# cat example.sh
2#!/bin/bash
3
4string="Bigdata process framework is Hadoop,Hadoop is an open source project"
5
6function print_tips
7{
8 echo "********************************"
9 echo "(1)打印string长度"
10 echo "(2)删除字符串中所有的Hadoop"
11 echo "(3)替换第一个Hadoop为Mapreduce"
12 echo "(4)替换全部Hadoop为Mapreduce"
13 echo "********************************"
14}
15function len_of_string
16{
17 echo "${#string}"
18}
19function del_hadoop
20{
21 echo "${string//Hadoop/}"
22}
23function rep_hadoop_mapreduce_first
24{
25 echo "${string/Hadoop/Mapreduce}"
26}
27function rep_hadoop_mapreduce_all
28{
29 echo "${string//Hadoop/Mapreduce}"
30}
31
32while true
33do
34 echo "[string=$string]"
35 echo
36 print_tips
37 read -p "Pls input your choice(1|2|3|4|q|Q):" choice
38
39 case $choice in
40 1)
41 len_of_string
42 ;;
43 2)
44 del_hadoop
45 ;;
46 3)
47 rep_hadoop_mapreduce_first
48 ;;
49 4)
50 rep_hadoop_mapreduce_all
51 ;;
52 q|Q)
53 exit
54 ;;
55 *)
56 echo "Error,input only in (1|2|3|4|q|Q)"
57 esac
58done
59
命令替换
`` 和 $()两者是等价的
$(())主要用来进行整数运算,包括加减乘除
1# 获取系统所有用户并输出
2[root@localhost ~]# cat user.sh
3#!/bin/bash
4#
5index=1
6for user in `cat /etc/passwd | cut -d ":" -f 1`
7do
8 echo "This is $index user: $user"
9 index=$(($index + 1))
10done
11
12
13# 根据系统时间计算今年或明年
14[root@localhost ~]# echo "This is $(($(date +%Y) + 1)) year"
15This is 2022 year
16
17# 根据系统时间获取今年还剩多少星期,已经过了多少星期
18[root@localhost ~]# echo "This year have passed $(date +%j) days"
19This year have passed 135 days
20[root@localhost ~]# echo "This year have passed $(($(date +%j)/7)) weeks"
21This year have passed 19 weeks
22
23[root@localhost ~]# echo "There is $((365 -$(date +%j))) days before new year"
24There is 230 days before new year
25[root@localhost ~]# echo "There is $(((365 -$(date +%j))/7)) weeks before new year"
26There is 32 weeks before new year
27
28# 判断nginx 进程是否存在,若不存在则自动拉起该进程
29[root@localhost ~]# cat nginx.sh
30#!/bin/bash
31#
32
33nginx_process_num=$(ps -ef | grep nginx | grep -v grep | wc -l)
34if [$nginx_process_num -eq 0];then
35 systemctl start nginx
36fi
expr
1[root@localhost ~]# num1=17
2[root@localhost ~]# num2=5
3[root@localhost ~]# num3=`expr $num1 + $num2`
4[root@localhost ~]# echo $num3
522
6
7[root@localhost ~]# expr $num1 \* $num2
885
9
10[root@localhost ~]# num3=$(($num1*$num2))
11[root@localhost ~]# echo $num3
1285