目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

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

作者:Soulboy