shell

shell 速成

一 shell规范

命名规范

nginx_install.sh 脚本名称 脚本扩展名 .sh
名字不要太长 26个字节内

代码规范

1、#!/bin/bash
//脚本第一行, #!魔法字符,指定脚本代码执行的程序。即它告诉系统这个脚本需要什么解释器来执行,也就是使用
哪一种Shell

2、#代表注释,#!特例 

3、//以下内容是对脚本的基本信息的描述,大家可以根据实际情况尽可能的写详细一些,方便后续使用者
# Name: 脚本名字
# Desc:描述describe
# Path:存放路径
# Usage:用法
# Update:更新时间
# Author:作者
# Release: 分发版本

//下面就是脚本的具体内容
commands
...

执行方法

– 标准脚本执行方法(建议

授权
chmod +x  *.sh
执行
./*.sh

第二种脚本执行方法

授权
chmod 644  *.sh
执行
bash *.sh

shell 管道运用

> 重定向输入 覆盖原数据
>> 重定向追加输入,在原始数据的末尾添加
< 重定向输出      wc -l  < /etc/passwd
<< 重定向追加输出     fdisk /dev/sdb <<EOF .. EOF

二 变量

2.1 用途

1.减少手工命令的重复输入,一定程度上避免认为错误

2.将软件或者应用的安装及配置实现标准化

3.用于实现日常性,重复性的工作,文件打包,压缩备份,监控

2.1.2 命名规范

前提:简单明了

规范

变量名是由字母数字下划线组成

不能以数字开头

不能使用shell的关键字

不要使用中文的变量名

不能使用特殊符号

2.1.3 命名风格

纯小写字母加下划线

驼峰体

大写

2.2 如何使用变量

先定义,后引用

定义

例子: NAME=zhangsan #等号左右两边不能加空格

引用

​ $NAME

​ ${ NAME }

2.2.1 变量的三大组成部分

变量名:使用来访问变量值的

赋值符号: 把变量值的内存地址绑定给变量名

变量值:记录的十五的状态,即数据

2.2.2 变量赋值

(1) 直接赋值

NAME=name

(2) 脚本参数获取

# cat test1.sh 
#!/bin/bash 
echo $1 $2 $3 $4

bash test1.sh 1 2 3 4 5 
1 2 3 4

(3)与用户交互来获取变量值

read -p "请输入:" -t 5 -n 2 NAME

-t 5 # 时间五秒失效

-n 2 #两个字符

#!/bin/bash 
read -p "请输入您的账号:" NAME

if [ $NAME == name ];then
  echo "用户正确"
    else
  echo "用户错误"
fi


bash  test1.sh 
请输入您的账号:name    
用户正确

预定变量

位置变量 作用说明
$# 获取当前执行的shell脚本后面接的参数的总个数
$* 获取当前shell脚本所有传参的参数,不加引号和$@相同;如果给$加上双引号,例如:"$",则表示将所有的参数视为单个字符串,相当于“$1 $2 $3”
$@ 获取当前shell脚本所有传参的参数,不加引号和$相同;如果给$@加上双引号,例如:“$@”,则表示将所有的参数视为单个字符串,相当于"$1” "$2" " $3" ".....",这是将多参数传递给其他程序的最佳方式,因为它会保留所有的内嵌在每个参数里的任何空白,当“$@”和"$"都加上双引号时,两者都是有区别的;都不加双引号时,两者无区别
$0 获取当前执行的shell脚本的文件名,如果执行脚本包含了路径,那么就包括脚本路径
$n 获取当前执行的shell脚本的第N个参数值,n=1..9,当n为0时,表示脚本的文件名,如果n大于9,则用大括号括起来,接的参数要以空格分开哦。

三 格式化输出

我们在使用shell写一个程序的时候,如果想让广大的用户都能使用,都能快速上手,那么好的交互界面就太重要了。我们可以使用多种方法开发好的、易交互的界面,常用的工具有:dialog、echo、printf等命令。

1.echo

语法:echo [-ne][字符串]

补充说明:
1、echo会将输入的字符串送往标准输出。
2、输出的字符串间以空白字符隔开,并在最后加上换行号。

OPTIONS:
-n	不要在最后自动换行
-e	若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:

转义字符
a	发出警告声;
	删除前一个字符;
		插入tab;

	换行且光标移至行首;

c	最后不加上换行符号;
f	换行但光标仍旧停留在原来的位置;

	光标移至行首,但不换行;
v	与f相同;
		插入字符;
nnn	打印nnn(八进制)所代表的ASCII字符;  备注:数字0  不要理解成字母o
xNN  打印NN(十六进制)所代表的ASCII字符;

-–help	显示帮助
-–version显示版本信息

2.输出颜色字体

echo 显示带颜色需要使用参数 -e

格式如下:
echo -e "33[字背景颜色;文字颜色m字符串33[0m"

例如: echo -e “33[41;36m something here 33[0m”
其中41的位置代表底色, 36m的位置是代表字的颜色

1、字背景颜色和文字颜色之间是英文的
2、文字颜色后面有个m
3、字符串前后可以没有空格,如果有的话,输出也是同样有空格

下面是相应的字和背景颜色,可以自己来尝试找出不同颜色搭配

 echo -e “33[31m 红色字 33[0m”
  echo -e “33[34m 黄色字 33[0m”
  echo -e “33[41;33m 红底黄字 33[0m”
  echo -e “33[41;37m 红底白字 33[0m”
  
字颜色:30—–37
  echo -e “33[30m 黑色字 33[0m”
  echo -e “33[31m 红色字 33[0m”
  echo -e “33[32m 绿色字 33[0m”
  echo -e “33[33m 黄色字 33[0m”
  echo -e “33[34m 蓝色字 33[0m”
  echo -e “33[35m 紫色字 33[0m”
  echo -e “33[36m 天蓝字 33[0m”
  echo -e “33[37m 白色字 33[0m”

  
字背景颜色范围:40—–47
  echo -e “33[40;37m 黑底白字 33[0m”
  echo -e “33[41;37m 红底白字 33[0m”
  echo -e “33[42;37m 绿底白字 33[0m”
  echo -e “33[43;37m 黄底白字 33[0m”
  echo -e “33[44;37m 蓝底白字 33[0m”
  echo -e “33[45;37m 紫底白字 33[0m”
  echo -e “33[46;37m 天蓝底白字 33[0m”
  echo -e “33[47;30m 白底黑字 33[0m”
  
最后面控制选项说明
  33[0m 关闭所有属性
  33[1m 设置高亮度
  33[4m 下划线
  33[5m 闪烁
  33[7m 反显
  33[8m 消隐

  33[30m — 33[37m 

设置前景色
  33[40m — 33[47m 设置背景色
  
  
  33[nA 光标上移n行
  33[nB 光标下移n行
  33[nC 光标右移n行
  33[nD 光标左移n行
  33[y;xH设置光标位置
  33[2J 清屏
  33[K 清除从光标到行尾的内容
  33[s 保存光标位置
  33[u 恢复光标位置
  33[?25l 隐藏光标
  33[?25h 显示光标
  
用法例子  光标下移三行  
[root@zutuanxue ~]# echo -e "33[0m today is fine 33[3B"

 today is fine 

1628593260498

案例要点:

  • echo输出缩进问题

  • 字体颜色输出

    cat fruits_shop.sh 
    
    #!/bin/bash
    # 
    #Author: LZL
    #Release: 
    #Description: 水果
    
    echo -e "		    33[32m Fruits List 33[0m      
    "
    echo -e "	   33[31mFruit33[0m   		 33[31mPrice33[0m 		33[31mWeight33[0m"
    echo -e "	33[34m1)Apple		¥10.00		1KG33[0m"
    echo -e "	33[34m2)Banana	¥9.00		1KG33[0m"
    echo -e "	33[34m3)Orange	¥15.20		1KG33[0m"
    

四 脚本用户交互

1.read

功能:默认接受键盘的输入,回车符代表输入结束

应用场景:人机交互

命令选项
-p打印信息
-t限定时间
-s不回显
-n输入字符个数

job实现步骤:
1、根据linux文本界面登陆窗口输出信息,打印登陆提示信息
2、交互输入登陆账号
3、交互输入登陆密码

#!/bin/bash
# 
#Author: 
#Release: 
#Description: login

IP=`ifconfig ens33|egrep -w "inet"|awk '{print $2}'`

#1、清屏
clear
#2、输出提示信息
echo "CentOS Linux 8 (Core)"
echo -e "33[36m Kernel `uname -r` on an `uname -m`
 33[0m"

echo -e "Web console: https://localhost:9090/ or https://$IP:9090/ 
"

#3、交互输入登陆名
echo -n "$HOSTNAME login: "
read account

#4、交互输入密码
read -s -t30 -p "Password: " pw
echo

五 运算详解

计算机编程就是三大步:输入,运算,输出

常见的计算机运算

5.1 赋值运算
a=10
name='baism'

字符串必须用引号引起来
5.2 算术运算

四则运算: + - * 【加,减,乘,除】

5.3 整数运算
  • expr

  • let

  • $(())

  • bc

5.3.1 expr

expr 命令 只能做整数运算,格式比较古板,注意空格

[root@localhost ~]# expr 1+1         `运算时注意空格距离
1+1

[root@localhost ~]# expr 1 + 1
2

[root@localhost ~]# expr 4 / 2
2

[root@localhost ~]# expr 4 * 2
8

[root@localhost ~]# expr 4 - 2
2
5.3.2 let

let 命令只能做整数运算,且运算元素必须是变量,无法直接对整数做运算

let a=100+3;echo $a
103


let a=100-3;echo $a
97


let a=100/3;echo $a
33


let a=100*3;echo $a
300
5.2.3 小括号

小括号运算,在shell中(( ))也可以用来做数学运算

echo $((100+3))      加
103

echo $((100-3))      减 
97

echo  $(( 10*3 ))    乘
30

echo  $(( 10/3 ))    除
3


$((100%3))           余
1

echo $((10**3))     #开方运算
1000
5.4 浮点运算

浮点运算是采用的命令组合的方式来实现的 echo “scale=N;表达式”|bc

scale=N N 代表取值小数点后多少位

[root@localhost ~]# echo  "scale=3;100/3"|bc
33.333
scale=3  只取小数点后三位
5.5 比较运算
5.5.1 比较运算
-eq 等于
-gt 大于
-lt 小于
-ge 大于或等于
-le 小于或等于
-ne 不等于
#!/bin/bash
if [ $1 -gt $2  ];then
  echo "$1 大于 $2"
 elif [ $1  -lt $2  ];then 
  echo "$1 小于  $2"
 else 
  echo "$1 等于 $2"
fi
[root@localhost ~]# bash yunsuan.sh  2 1 
2 大于 1
[root@localhost ~]# bash yunsuan.sh  1 2
1 小于  2
[root@localhost ~]# bash yunsuan.sh  1 1
1 等于 1
5.2.2 test 测试比较

test 比较时,

并且不会返回结果,需要通过$?才能看到结果

test 100 -gt 300;echo $?     
1

test 100 -lt 300;echo $?
0
5.3.3 字符串比较运算

运算符

== 等于
!= 不等于
-n 检查字符串的长度是否大于0
-z 检查字符串的长度是否为0
5.6 逻辑运算

完成一个任务,需要多个条件或者满足多个条件中的一个即可。

&& 逻辑【与】运算
|| 逻辑【或】运算
逻辑【非】运算
案例:
案例需求
伟大、慈祥的丈母娘有女儿,她想给自己的女儿选一个女婿,所以就想通过网上招婿的方式去处理,为了节约成本,让你帮忙开发一个小程序来自动过滤一下不满足条件的男士。
改程序为了能够满足大量丈母娘的需求,所以可以根据女儿的年龄做出不同的判断

姑娘20岁 应征男士条件:房子需要两套及以上、存款100W及以上、车子1辆以上,条件必须全部满足
姑娘30岁 应征男士条件:房子需要两套及以上、存款100W及以上、车子1辆以上,条件满足其中一个即可
姑娘40岁 应征男士条件:是男的都可以报名
注意:应征者必须全是男性
案例思考
因为是多条件判断,复合逻辑运算的条件,重点在不同年龄段的逻辑判断方式!

案例步骤

1、要求传入两个参数:姑娘年龄、应征者行吧
2、交互输入用户条件
3、判断用户条件并输出结果
#!/bin/bash
# 
#Author:
#
#Release: 
#Description: 丈母娘选女婿  练习逻辑运算

cat <<EOF
游戏规则:
    1)根据交互输入信息,让脚本去判断是否满足条件。
    2)判断条件如下:
        第一次 姑娘20岁    要求应征男子报名条件 房子需要两套及以上、存款100W及以上、车子1辆以上
	第二次 姑娘30岁               			以上条件满足一个即可
	第三次 姑娘40岁					是男的都可以报名
    3) 脚本执行方法  $0 姑娘年龄[20|30|40] 应征者性别[男|女]
EOF


#1、判断传递参数数量,要求两个
if [ $#  !=  2 ];then
   echo 'need two args $1 $2'

   exit 1
fi

if [ $2 == 男 ] ||  [ $2 == 女 ];then

echo " 您的性别是 $2 "
else
 echo "请正确输入性别"
exit 1
fi

#2、交互输入
read -p "请输入你的存款: " money
read -p "请输入你的房子数量: " zhangse
read -p "请输入你车子的数量: " car

#3、判断应征条件,并给出结果
#姑娘20岁代码
if [ $1 -eq 20 ] && [ $money -gt 1000000 ] && [ $zhangse -ge 2 ] && [ $car -ge 1 ] && [ "$2" == "男" ];then
    echo "初始通过,等待姑娘复试吧"
#姑娘30岁代码
elif [ $1 -eq 30 ] && [ "$2" == "男" ] && ( [ $money -gt 1000000 ] || [ $zhangse -ge 2 ] || [ $car -ge 1 ] );then
    echo "初始通过,等待姑娘复试吧"
#姑娘40岁代码
elif [ $1 -eq 40 ] && [ ! $2 == "女" ];then
    echo "初始通过,等待姑娘复试吧"
else
   echo "你不满足条件,byebye"
fi
5.7 文件判断

linux的设计思路:一切皆文件,对文件系统的操作其实可以狭隘的理解为对文件的操作。如果希望对文件类型和权限或者两个文件做新旧或者是否同一个文件进行判断。

-d 检查文件是否存在且为目录
-e 检查文件是否存在
-f 检查文件是否存在且为刻度文件
-r 检查文件是否可读
-s 检查文件是否存在且不为空
-w 检查文件是否存在且可写
-x 检查文件是否存在且可执行
-O 检查文件是否存在且被当前用户拥有
-G 检查文件是否存在并且默认组为当前用户组
-nt file1-nt file2 检查file1 是否比file2 新
-ot file1 -ot file2 检查file1 是否比file2旧
-ef file1 是否与file2是同一个文件,判断
test -f zmn.sh;echo $?      【 zmn.sh 这个文件是我已经创建出来的】
0

test -f zmn1.sh;echo $?
1
案例:

写一个平滑关闭服务脚本

案例思路

判断服务进程文件是否存在,存在读取PID并判断是否存在进程
进程存在就使用Kill命令结束服务
不存在就报“服务已经结束“
案例步骤
1、检查服务PID文件
2、检查进程是否存在
3、杀死进程

脚本

#!/bin/bash
# 
#Author: 
#
#Release: 
#Description:找到服务的PID号,如果服务开启则杀死,否则提示服务已经关闭或不存在

#1、判断PID
#注意PID的路径,如果服务的PID不在这里可以做个软连接
if [ -f /var/run/$1.pid ];then
   #2、如果存在
   PID=`cat /var/run/$1.pid`
   #3、统计进程数
   process_num=`ps aux|grep $PID|wc -l`
   #5、判断进程数大于2则杀死
   if [ $process_num -ge 2 ];then
       kill -s QUIT $PID 
   else
   #5、判断小于2则提示进程不存在,同时删除服务PID文件
   	echo "service $1 is close"
        rm -f /var/run/$1.pid
   fi
else
   #2、不存在
   echo "service $1 is close"
fi

六 数组

6.1 数组定义

6.2 数组赋值方式

6.3 取值方式

定义:

数组可以让用户一次赋予多个值,需要读取数据时只需通过索引调用就可以方便读出了。

普通数组:只能使用整数作为数组索引(元素的索引)
关联数组:可以使用字符串作为数组索引(元素的索引)

6.1数组定义
数组名称=(元素1 元素2 元素3 ...)
array1= (a b c d e f g)
6.2 数组赋值方式

1次赋值

array1= (a b c d e f g)

1次赋多个值

array=(var1 var2 var3 var4)
array1=(`cat /etc/passwd`)			//将文件中每一行赋值给array1数组
array2=(`ls /root`)
array3=(harry amy jack "Miss zhang")
array4=(1 2 3 4 "hello world" [10]=linux)

分别赋值

array2[0]=1
array2[1]=2
array2[10]=11

命令执行结果赋值

array3=(`cat /etc/passwd`)     //将文件中每行赋值给array1数组

个性化赋值

array4=(1 2 3 "hello world" [8]="haha")
6.3 取值方式

${数组名称[索引]}

默认情况下索引是指数组中的元素【存在值】在数组中的顺序,从0开始计数,关联数组除外,比如

array=( var1 var2 var3 var4 )

array数组中存有4个元素,分别是:var1 var2 var3 var4

取出var2这个元素 就需要看他在数组中的位置

元素 var1 var2 var3 var4
索引 0 1 2 3

所以上述中,取出var2元素的正确方式:${array[1]}

数组取值练习

${array[i]}  i表示元素的索引
使用@ 或 * 可以获取数组中的所有元素:
获取第一个元素
echo ${array[0]}
echo ${array[*]}			获取数组里的所有元素
echo ${#array[*]}			获取数组里所有元素个数
echo ${!array[@]}    	获取数组元素的索引索引
echo ${array[@]:1:2}    访问指定的元素;1代表从索引为1的元素开始获取;2代表获取后面几个元素

6.4关联数组

关联数组使用首先要申明该数组为关联数组,申明方式,declare -A 数组名称

首先声明关联数组
declare -A asso_array1
declare -A asso_array2
declare -A asso_array3

一次附多个值

asso_array2=([name1]=harry [name2]=jack [name3]=amy [name4]="Miss zhang")

查看关联数组

declare -A
declare -A asso_array1='([php]="three" [java]="two" [linux]="one" )'
declare -A asso_array2='([name3]="amy" [name2]="jack" [name1]="harry" [name4]="Miss zhang" )'

管理数组取值

echo ${asso_array1[linux]}
one
 
echo ${asso_array1[php]}
three

echo ${asso_array1[*]}
three two one

echo ${!asso_array1[*]}
php java linux

echo ${#asso_array1[*]}
3

echo ${#asso_array2[*]}
4

echo ${!asso_array2[*]}
name3 name2 name1 name4

七 if判断语句

7.1 单 if 使用

2.if..else

3.if..elif..else

4.if 嵌套if

5.if 高级用法

7.1 单 if 判断

一部判断,条件返回值为真,做什么操作(command)

if [ condition ];then              #condition 值为true or       false  
commands                           #代码块 一行或者多行代码     fi                                 # 结束判断
流程判断
             开始
              |
              v
  错(F)《--条件判断——》真(T)
  |                     |      
  |                     |
  V         【执行命令】《--
 退出【end】

案例

判断登录用户是否为root用户
#!/bin/bash
#Author: lzl
#Created Time: 
#Script Description: 

if [ $USER != 'forest' ]
   then
	echo "ERROR: need to be root so that"
	exit 1
fi
7.2 if ..else

两步判断方式,条件为真,进行什么操作;条件是假执行什么操作(commands)

if  [ condition ];then    #条件为真
                         
  commands1            #真;执行的代码块
else                   #条件为假
  commands2            #假; 要执行的代码块                  
fi

释意
假如条件为真
  那么

        执行commands1代码块
否则
        执行commands2代码块
结束

7.3 if elif...else

用于两个以上的判断结果,也就是多于一个以上的判断条件

if [ condition 1]     满足第一个条件

     then          真

            command1    执行command1代码块
elif [ condition 2]   满足第二个条件
 
     then           真

             commands2    执行command2代码块

  .......
else      如果条件都不满足

            commandsX      执行commandX代码块
fi    结束判断
7.4 if 嵌套 if

多步判断,类似于多条件if

依赖执行环境 configure>make>make install

案例1

6.1、使用if嵌套if的方式判断两个整数的关系
#!/bin/bash
#Author: 
#Created Time: 
#Script Description: 

if [ $1 -ne $2 ]
   then
       if [ $1 -gt $2 ]
  	  then
		echo " $1 > $2 "
       else
		echo " $1 < $2 "
       fi
else
       echo " $1 = $2 "
fi

案例2

写一个业务初始化的脚本,完成nginx软件的安装

案例思考

1.nginx 软件包获得的方式

2.nginx 安装流程

3.nginx 安装依赖关系

案例步骤

1.软件包下载

2.软件包解压

3.安装依赖

4.安装nginx

5.返回结果

#!/bin/bash
#Author: 
#Created Time: 
#Script Description: nginx aoto install script


source_pkg=nginx-1.19.2.tar.gz
#1、软件包下载
wget http://nginx.org/download/$source_pkg 
#2、解压
if [ -f $source_pkg ];then
	tar xf $source_pkg && cd nginx-1.19.2
else
        echo "not found $source_pkg"
	exit 1
fi

#3、安装依赖包
if ! ( yum -y install pcre-devel zlib-devel );then
      echo "yum: install soft error"
      exit 1
fi

#4、配置
#判断配置语句执行结果
if ./configure 1>/dev/null        
	then
	#判断make执行结果
	     if make 1>/dev/null
		 then
		 #判断make install安装结果
			if make install 1>/dev/null
			   then
			 	echo "nginx 安装成功"
			else
			 	echo "nginx 安装失败"
				exit 1
		        fi
		else
			echo "make fail"
			exit 1
		fi
else
		echo "configure fail"
		exit 1
fi



#./configure
#if [ $? -eq 0 ];then

#注意: 1>/dev/null
1  标准输出
2  标准错误输出
7.5 if 高级用法

使用双圆括号,可以在条件中植入数学表达式if (())

#!/bin/bash
#Author:
#Created Time:
#Script Description: 

if (( (5+5-5)*5/5 > 10 ))
    then
        echo "yes"
else
        echo "no"
fi

使用双中括号 [[ ]] 可以在条件中使用通配符

通过案例看下,为字符串提供高级功能 模式匹配 r* 匹配r开头的字符串

#!/bin/bash
#Author: 
#Created Time: 
#Script Description: 
for var in  ab ac rx bx rvv vt
   do
       if [[ "$var" == r* ]]
	  then
		echo "$var"
       fi
done
7.6 if 语法格式简写

省去了关键字;

条件为真采用&& 符号链接命令块;

条件为假采用 || 符号链接命令块;

案例

if [ ! -d /tmp/baism ]
    then
        mkdir /tmp/baism
fi

可以简写为

[ ! -d /tmp/baism ] && mkdir /tmp/baism

if [ $USER == 'root' ]
	  then
	      echo "hello root"
else
			  echo "hello guest"
fi

可以简写
[ $USER == 'root' ]&&echo "hello root" || echo "hello guest"
原文地址:https://www.cnblogs.com/zongliang-ya/p/15194708.html