## 1.shell基本语法

**什么是shell**

Shell是一个命令解释器，它在操作系统的最外层，负责直接与用户进行对话，把用户的输入解释给操作系统，并处理各种各样的操作系统的输出结果，输出到屏幕反馈给用户。这种对话方式可是交互也可以是非交互式的。我们所输入的命令计算机是不识别的，这时就需要一种程序来帮助我们进行翻译，变成计算机能识别的二进制程序，同时又把计算机生成的结果返回给我们。

![shell位置.png](https://s2.loli.net/2022/01/10/flNSJcE3swioKbt.png)

---

---


## 2.编程语言分类

编程语言主要用：<font color='red'>低级语言和高级语言</font>

(1)低级语言：

    机器语言：二进制语言
    
    汇编语言：符号语言，使用助记符来代替操作码，也就是用符号代替机器语言的二进制码它们都是面向机器的语言


​    
(2)高级语言：
​    
**它是比较接近自然语言或者说人类语言的一种编程，用人们能够容易理解的方式进行编写程序**

    静态语言：编译型语言如：c、c++、java，
    动态语言：解释型语言如：php、shell、python、go

**gcc编译器：（解释器）将人类理解的语言翻译成机器理解的语言**

---

---



## 3.系统默认的shell

    [root@master ~]# cat /etc/shells   #查看系统支持的shell
    /bin/sh
    /bin/bash
    /sbin/nologin
    /usr/bin/sh
    /usr/bin/bash
    /usr/sbin/nologin
    /bin/zsh
    [root@master ~]# 

**zsh、tcsh、csh需要安装的shell**

**注：/bin/sh已经被/bin/bash所替换，/bin/csh已经被/bin/tcsh所替换**


---


#### bash的好处：
1. 历史命令
1. 命令与文件补全功能（TAB补全键）
1. 命令别名设置功能
1. 任务管理、前台、后台控制
1. 程序化脚本
1. 通配符

---

---


## 3. 什么是shell脚本
**shell脚本：就是说我们把原来linux命令或语句放在一个文件中，然后通过这个程序文件去执行时，我们就说这个程序为shell脚本或shell程序；我们可以在脚本中输入一系统的命令以及相关的语法语句组合，比如变量，流程控制语句等，把他们有机结合起来就形成了一个功能强大的shell脚本。可以理解为**<font color='red'>**命令拼多多**</font>

**脚本初体验：**

    [root@master opt]# ls   #查看/opt/路径下面有什么东西
    [root@master opt]# vim test.sh   #创建一个.sh文件，注意Linux不是根据
    #文件后缀名识别文件的，是根据inode识别的


​    #test.sh文件插入以下内容：
​    #!/bin/bash
​    #This is shell.
​    echo "hello word"
​    mkdir /opt/test
​    touch /opt/test/a.txt b.txt
​    
​    [root@master opt]# sh test.sh   #执行test.sh脚本（文件）
​    hello word
​    [root@master opt]# ls   #查看已经创建好test目录以及b.txt文件
​    b.txt  test  test.sh
​    [root@master opt]# ls /opt/test
​    a.txt
​    [root@master opt]# 

---


**注释：**

**1、#!/bin/bash作用：告诉脚本使用的是哪种命令解释器。如不指shell，以当前shell作为执行的shell。**

**2、在shell中以#表示开头，整个行就被当作一个注释。执行时被忽略。**

**3、shell脚本程序一般以.sh结尾。**

**4、shell脚本一般在开头注明：作者，时间，联系方式，注意事项**

---

**创建脚本并运行其他方法**
    

    [root@master opt]# vim c.txt
    [root@master opt]# chmod +x /opt/c.txt   #添加执行权限
    [root@master opt]# ll -a /opt/c.txt   #成功添加权限
    -rwxr-xr-x. 1 root root 46 1月  10 19:20 /opt/c.txt
    [root@master opt]# ./c.txt   #当前目录下的c.txt，这样子相当于Windows的双击执行
    hello word
    [root@master opt]# bash c.txt   #使用bash(sh)命令启动
    hello word
    [root@master opt]# /opt/c.txt   #使用绝对路径执行；其实就是相当于我们平时使用的cd、mv等命令的本质操作，
    #输入cd其实是去到/usr/bin/cd找到对应的二进制文件进行
    hello word
    [root@master opt]# sh c.txt   #使用sh(bash)命令启动
    hello word
    [root@master opt]# 


---


**创建shell程序的步骤：**

第一步：创建一个包含命令和控制结构的脚本文件。

第二步：使用chmod +x c.sh

第三步：检测语法错误

第四步：执行./c.sh

---



**shell脚本的执行通常有以下几种方式:**

1、./test.sh(以路径执行脚本的话要有执行权限chmod +x test.sh)

2、/root/test.sh(绝对路径)

3、bash  test.sh或sh  test.sh（这种方式可以不对脚本文件添加执行权限）

4、source    test.sh或  .  test.sh  (可以没有执行权限)

5、sh <test.sh或者cat   test.sh|sh(bash)

---


方法一：切换到shell脚本所在的目录（此时，称为工作目录）执行shell脚本：

方法二：以绝对路径的方式去执行bash shell脚本：

方法三：直接使用bash 或sh 来执行bash shell脚本：

方法四：用source或(.  xxx.sh)执行bash shell脚本：

<font color='red'>前三种方法执行shell脚本时都是在当前父进程开启一个子进程环境，此shell脚本就在这个子进程环境中执行。shell脚本执行完后子进程环境随即关闭，然后又回到父进程中。而方法四则是在当父进程中执行的。</font>

<font color='red'>前三种方法执行脚本调用的环境变量只有3个，如下例1所示，只有第4种方法才能调用例2的环境变量</font>

例1：

[root@handsome opt]# bash
/etc/profile.d/1.sh
/etc/bashrc
/root/.bashrc

例2：

[root@handsome opt]#

/etc/profile.d/1.sh
/etc/profile
/etc/bashrc
/root/.bashrc
/root/.bash_profile

注：可以使用ps -auxf 查看


---

---
## shell变量及运用

**什么是shell变量：** **<font color='red'>简单地说，就是让某一个特定字符串代表不固定的内容。</font>**

**变量能用来代表每个值的符号名,也是shell传递数据的一种方法。变量最大的好处就是：方便**

==**变量的设置规则：**==

**1、变量名称通常是大写字母，它可以由数字、字母（大小写）和下划线_组成。变量名区分大小写；但是大家要注意** **<font color='red'>变量名称不能以数字开头</font>**

**2、等号=用于为变量分配值，在使用过程中** **<font color='red'>等号两边不能有空格</font>**

**3、变量存储的数据类型是数值和字符串值**

**4、在对变量赋于字符串值时，建议大家用引号将其括起来。** **<font color='red'>因为如果字符串中存在空格符号、标点符号时。需要使用单引号或双引号</font>**

**5、要对变量进行调用，可以在变量名称前加美元符号** **<font color='red'>$</font>**

**6、如果需要增加变量的值，那么可以进行变量值的叠加。不过变量需要用双引号包含** **<font color='red'>“$变量名”</font>** **或用** **<font color='red'>${变量名}包含</font>**



## 5.变量的分量

**按照变量作用域可以分成2类：全局变量和局部变量。**

**<font color='purple'>局部变量</font>**
**是shell程序内部定义的，其使用范围仅限于定义它的程序，对其它程序不可见。包括：用户自定义变量、位置参数变量和预定义变量。**

1、用户自定义变量

2、位置参数变量：这种变量主要是用来向脚本当中传递参数或数据的，变量名不能自定义，变量作用是固定的。

3、预定义变量：是Bash中已经定义好的变量，变量名不能自定义，变量作用也是固定的。

**<font color='purple'>全局变量</font>** **也是环境变量，其值不随shell脚本的执行结束而消失。**

1、环境变量：这种变量中主要保存的是和系统操作环境(/etc)相关的数据。
<font color='red'>为了区别与自定义变量的不同，环境变量通常以大写字符来表示</font>



## 6.用户自定义变量
    例子1：给变量VAR1赋值
    [root@master opt]# VAR1=123
    [root@master opt]# echo $VAR1 
    123
    [root@master opt]# 
    
    例子2：错误的赋值方式,不允许数字开头，等号两边不能有空格
    [root@master opt]# VAR2 =456
    -bash: VAR2: 未找到命令
    [root@master opt]# VAR2= 456
    -bash: 456: 未找到命令
    [root@master opt]# VAR2 = 456
    -bash: VAR2: 未找到命令
    [root@master opt]# 3VAR2 = 456
    -bash: 3VAR2: 未找到命令
    [root@master opt]# 3VAR2=456
    -bash: 3VAR2=456: 未找到命令
    
    例子3：变量值的叠加，使用${}
    $name是${name}的简化版本，但是在某些情况下，还必须使用花括号引起的方式来消除歧义并避免意外的结果
    [root@master opt]# VAR4=mysql
    [root@master opt]# echo $VAR4
    mysql
    [root@master opt]# echo $VAR4-db.log
    mysql-db.log
    [root@master opt]# echo $VAR4.db.log
    mysql.db.log
    [root@master opt]# echo $VAR4db.log    #发现输出的结果不是我们想要的，怎么办？
    .log
    [root@master opt]# echo ${VAR4}db.log
    mysqldb.log
    [root@master opt]# echo "$VAR4"db.log
    mysqldb.log


​    
​    
​    例子4：变量切片
​    [root@exrcise1 opt]# name="I am headsome boy"
​    [root@exrcise1 opt]# echo $name
​    I am headsome boy
​    [root@exrcise1 opt]# echo ${name:2:2}					#第一个2是指从第几个字符后面开始提取，第二个2是批截取几个字符
​    am
​    [root@exrcise1 opt]# echo ${name:2:1}
​    a


​    
​    例子5：变量换行输出
​    [root@exrcise1 opt]# echo $name |xargs -n2		#每2个字符串就输出一次
​    I am
​    headsome boy


​    
​    例6：变量的删除
​    #从前面往后删除，可以使用通配符匹配字符串
​    [root@exrcise1 opt]# url=www.uplooking.com
​    [root@exrcise1 opt]# echo $url
​    www.uplooking.com
​    [root@exrcise1 opt]# echo ${url#.}
​    www.uplooking.com
​    [root@exrcise1 opt]# echo ${url#*.}
​    uplooking.com
​    [root@exrcise1 opt]# echo ${url#www.}
​    uplooking.com
​    

    ##贪婪匹配，删除到最后一个.
    [root@exrcise1 opt]# echo ${url#www.uplooking.}
    com  
    [root@exrcise1 opt]# echo ${url##*.}
    com


​    %从后面往前面删除，可以使用通配符匹配字符串
​    [root@exrcise1 opt]# url=www.uplooking.com
​    [root@exrcise1 opt]# echo $url
​    www.uplooking.com
​    [root@exrcise1 opt]# echo ${url%*.}
​    www.uplooking.com
​    [root@exrcise1 opt]# echo ${url%.*}
​    www.uplooking
​    [root@exrcise1 opt]# echo ${url%.*.*}
​    www
​    %%贪婪匹配，删除到最面前一个.
​    [root@exrcise1 opt]# echo ${url%.uplooking.com}
​    com  
​    [root@exrcise1 opt]# echo ${url%%.*}
​    com
​    

    常应用：
    [root@exrcise1 opt]# num=100%
    [root@exrcise1 opt]# echo $num
    100%
    [root@exrcise1 opt]# 
    [root@exrcise1 opt]# echo ${num%%}
    100%
    [root@exrcise1 opt]# echo ${num%\%}
    100
    [root@handsome opt]# echo ${var1%"%"}
    100
    [root@handsome opt]# echo ${var1%'%'}
    100
    


​    
​    例7：变量的替换
​    
    [root@exrcise1 opt]# echo $url
    www.uplooking.com
    [root@exrcise1 opt]# echo ${url/www/test}
    test.uplooking.com
    [root@exrcise1 opt]# echo ${url/ook/oak}
    www.uploaking.com
    //贪婪替换,会全部替换
    [root@exrcise1 opt]# echo ${url//w/t}
    ttt.uplooking.com


​    

## 7.环境变量

**在shell中，变量分为两类：全局变量和局部变量**

**全局变量：对于shell会话和所有的子shell都是可见的**

**局部变量：它只在自己的进程当中使用**

---

**例1：** **<font color='red'>env</font>** **命令查看全局变量**
    

    [root@master opt]# env
    
    [root@master opt]# env |grep PATH
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

---



**例2：局部变量**

    [root@master opt]# VAR10=123   #设置局部变量
    [root@master opt]# echo $VAR10
    123
    [root@master opt]# bash   ==> 进入另一个子进程
    [root@master opt]# echo $VAR10   ==>访问不到$VAR10的值
    
    [root@master opt]# exit
    exit
    [root@master opt]#
    
    ###bash进入子进程其实就是本终端为父进程，在父进程里面创一个子进程，还是这个终端

---

**例3：使用** **<font color='red'>export</font>** **把这个局部变量输出为全局变量**

    [root@master opt]# export VAR11=today
    [root@master opt]# echo $VAR11
    today
    [root@master opt]# bash   ==>进入另一个子进程
    [root@master opt]# echo $VAR11   ==>引用全局变量成功
    today
    [root@master opt]# 


​    
**<font color='red'>注意：</font>**

虽然我们设置了export全局变量，但是新开的xshell连接中，还是读不到变量VAR11，怎么办？
![bash.png](https://s2.loli.net/2022/01/10/4wl5UKWBdChszfF.png)

解释：每一个终端都是一个独立的进程，所以在master[0]终端操作才有，master[1]则不存在VAR11
解决：让变量永久生效，可以把定义好的变量写入配置文件/etc/profile

    [root@master opt]# vim /etc/profile
    ###文件最后插入变量
    VAR12=this is a test
    [root@master opt]# source /etc/profile   #刷新一下

---

**当登录系统或新开启一个ssh连接启动bash进程时，一定会加载这4个配置文件：**



 /etc/profile            #系统全局环境和登录系统的一些配置

 /etc/bashrc             #shell全局自定义配置文件，用于自定义shell

 /root/.bashrc           #用于单独自定义某个用户的bash

 /root/.bash_profile     #用户单独自定义某个用户的系统环境


测试4个文件加载顺序：

    ###可以每个文件的最后，追加一个echo命令，输出一下文件的名字
    
    [root@master opt]# echo 'echo /etc/profile' >> /etc/profile
    [root@master opt]# echo 'echo /etc/bashrc' >> /etc/bashrc
    [root@master opt]# echo 'echo /root/.bashrc' >> /root/.bashrc
    [root@master opt]# echo 'echo /root/.bash_profile' >> /root/.bash_profile
    
    ###测试完别忘记进入这四个文件把追加进去的命令删掉，
    ###不然每次进去都会提示


![echo.png](https://s2.loli.net/2022/01/10/DRustoXhSxryNMa.png)



高危操作：

知道加载的顺序，可以在这里添加木马程序，只要管理登录系统，就触发木马程序！
现在大家知道学习操作系统原理的作用了吧。
<font color='red'>例子省略</font>


开始插入永久变量：

    [root@base ~]#vim /etc/profile   #在文件的最后插入
    export  VAR12=next   #=等号两边不能有空格
    [root@base ~]#source /etc/profile    #重新加载profile文件
    新打开的连接中，也有了



## 8.设置PATH环境变量

SHELL要执行某一个程序，它要在系统中去搜索这个程序的路径，path变量是用来定义命令和查找命令的目录，当我们安装了第三方程序后，可以把第三方程序bin目录添加到这个path路径内，就可以在全局调用这个第三方程序

例子：

    [root@base ~]# vim /opt/backup  
    #!/bin/bash 
    echo "Backup data is OK!" 
    [root@base ~]# chmod +x /opt/backup  
    [root@base ~]# /opt/backup 
    [root@base ~]# backup 
    bash: backup: 未找到命令... 
    将 backup 命令添加 PATH 中
    [root@base ~]# PATH=/opt/:$PATH 
    [root@base ~]# backup   #发现命令可以直接执行了，不用写全路径了 
    [root@base ~]# vim /etc/profile   #在文件最后追加以下内容，永久生效 
    export PATH=/opt/:$PATH 
    [root@base ~]# source /etc/profile   #重新加载配置文件，使用配置生效



## 9.shell中单引号和双引号区别(重点)

**'' 在单引号中所有的字符包括特殊字符($,'',`和\\)都将解释成字符本身而成为普通字符** **<font color='red'>(去除特殊含义)。</font>**

**"" 在双引号中，除了** **<font color='red'>$,"",`和\ </font>** **以外所有的字符都解释成字符本身** **<font color='red'>(去除特殊含义)。</font>**

**<font color='red'>$</font>** **拥有“调用变量的值”**

**<font color='red'>'',`</font>** **拥有引用命令的含义** 

**<font color='red'>\ </font>** **拥有“转义符”的特殊含义**

**注：** **<font color='red'>\转义符，跟在\之后的特殊符号将失去特殊含义，变为普通字符。如\$将输出“$”符号，而不当做是变量引用</font>**

    [root@master opt]# echo $VAR1
    123
    [root@master opt]# echo \$VAR1
    $VAR1
    [root@master opt]# 


---
    例子1：给变量值赋于多个单词，需要使用单引号和双引号
    [root@master opt]# VAR5='this is a good day'
    [root@master opt]# echo $VAR5
    this is a good day
    
     例子2：赋值时单引号和双引号的区别
    [root@master opt]# VAR6='good day $VAR1'
    [root@master opt]# echo $VAR6
    good day $VAR1
    [root@master opt]# VAR7="good day $VAR1"   #双引中$符号有作用
    [root@master opt]# echo $VAR7
    good day 123
    [root@master opt]# 
    ###注：单引号之间的内容原封不动赋值给变量，双引号之间的内容如有特殊符号会保留它的特殊含义


​    
​    例子3：单引号与双引号必须成对
​    [root@master opt]# VAR8='this's a good day'
​    > ^C
​    [root@master opt]# VAR8="this's a good day"
​    [root@master opt]# echo $VAR8
​    this's a good day
​    [root@master opt]# VAR8="this's a" good day"
​    > ^C
​    [root@master opt]# VAR8="this's "a" good day"
​    [root@master opt]# echo $VAR8
​    this's a good day
​    [root@master opt]# VAR8="this's "a" good' day"
​    [root@master opt]# echo $VAR8
​    this's a good' day


​    
​    例子4：删除变量（测试用）
​    [root@master opt]# unset VAR1
​    [root@master opt]# echo $VAR1





## 10.命令的替换,<font color='red'>使用$()或反引号``</font>

例子1：在命令就调用date命令

扩展：date命令是显示或设置系统时间与日期。

-s<字符串>：根据字符串来设置日期与时间。字符串前后必须加上双引号；

<+时间日期格式>：指定显示时，使用特定的日期时间格式。

例：格式化输出：
    
    [root@master opt]# date +"%Y-%m-%d"   #今天时间，一般备份数据需要用这个
    2022-01-10
    [root@master opt]# date +"%Y-%m"   #只显示年月
    2022-01
    [root@master opt]# date +"%Y-%m-%d %H:%M.%S"   #日期加时间
    2022-01-10 20:39.39
    [root@master opt]# date +"%Y/%m/%d %H/%M/%S"   #使用/做分隔符
    2022/01/10 20/39/59
    [root@master opt]# date +"%Y-%m-%d-%H-%M-%S"   #使用-做分隔符，一般备份数据需要用这个
    2022-01-10-20-41-19

---


<font color='red'>**注：**</font> 

%y 年份只显示 2 位， %Y 年份显示 4 位 

**date 命令加减操作：** 


date +%Y%m%d #显示当天年月日 

date -d "+1 day" +%Y%m%d #显示明天的日期 

date -d "-1 day" +%Y%m%d #显示昨天的日期 

date -d "-1 month" +%Y%m%d #显示上一月的日期 

date -d "+1 month" +%Y%m%d #显示下一月的日期 

date -d "-1 year" +%Y%m%d #显示前一年的日期 

date -d "+1 year" +%Y%m%d #显示下一年的日期 


![date.png](https://s2.loli.net/2022/01/10/bSoPzwjBNsUykHG.png)



**设定时间：** 

date -s 20180523 #设置成 20120523，这样会把具体时间设置成空 00:00:00 

date -s 01:01:01 #设置具体时间，不会对日期做更改 

date -s "2018-05-23 01:01:01" #这样可以设置全部时间

![date2.png](https://s2.loli.net/2022/01/10/52P6GdNvamDOEtr.png)


---


    例子2：在命令中调用date命令输出值
    [root@master opt]# echo `date`
    2018年 05月 23日 星期三 01:03:37 CST
    [root@master opt]# echo $(date)
    2018年 05月 23日 星期三 01:03:47 CST
    [root@master opt]# echo `date +"%Y-%m-%d"`
    2018-05-23





## 11.命令的嵌套使用，使用$($())

    [root@master opt]# find / -name "*.txt"
    
    [root@master opt]# VAR9=$(tar zcvf /opt/test.tar.gz /opt/ $(find / -name "*.txt" -exec cp {} /opt/test/ \;))
    
    [root@master opt]# echo $VAR9
    /opt/ /opt/test.sh /opt/test/ /opt/test/pkcs11.txt /opt/test/timedhosts.txt /opt/test/SOURCES.txt /opt/test/dependency_links.txt /opt/test/top_level.txt /opt/test/NOTICE.txt......
    
    骚操作：
    [root@master opt]# VAR9=$(tar zcvf /opt/test.tar.gz /opt/test $(find / -name "*.txt" -exec cp {} /opt/test \;))
    
    ### 不建议嵌套太多，两到三层即可



## 12.shell位置变量

**Shell解释执行用户的命令时，** **将<font color='red'>命令行</font>的第一个字符作为命令名，而其它字符作为参数。**

**$0获取当前执行shell脚本文件的文件名，包括脚本路径,命令本身**

**$n获取当前脚本的第n个参数n=1,2.....n   <font color='red'>当n大于9时用${10}表示。</font>**

例子：
    
    [root@master opt]# vim /opt/print.sh
    ###插入以下内容
    #!/bin/bash
    echo    "本shell脚本的文件名：$0"
    echo    "第1个参数：$1"
    echo    "第2个参数：$2"
    echo    "第3个参数：$3"
    echo    "第4个参数：$4"
    
    [root@master opt]# chmod +x print.sh 
    [root@master opt]# ./print.sh 1 22 333 4444 55555
    本shell脚本的文件名：./print.sh
    第1个参数：1
    第2个参数：22
    第3个参数：333
    第4个参数：4444
    [root@master opt]# 

使用场景：服务器启动传参数
​    [root@base ~]#/etc/init.d/network   restart   ==> #老运维就会这样做，这是centos6里面的操作，其实就是
​    #命令的本质(二进制)启动，这个/etc/init.d/network其实就是一个脚本传递了位置变量
​    

​    [root@exrcise1 ~]# grep '$0' /etc/init.d/network 
​        $0 stop
​        $0 start
​        echo $"Usage: $0 {start|stop|status|restart|reload|force-reload}"


---

---
## 13.特殊变量

有些变量是一开始执行Script脚本时就会设定，且不能被修改，但我们不叫它只读的系统变量，而叫它特殊变量。这些变量当一执行程序时就有了，以下是一些特殊变量：

变量 | 作用
---|---
$* | 以一个单字符串显示所有向脚本传递的参数；如"$*"用【"】括起来的情况、以"$1$2…$n"的形式输出所有参数
$@ | 以一个单字符串显示所有向脚本传递的参数; 与“$*”一样的作用 
$# | 传递到脚本的参数个数
$$ | 当前进程的进程号PID
$? | 显示最后命令的退出状态；0表示没有错误，其他任何值表明有错误
$! | 后台运行的最后一个进程的进程号pid
$_ | 表示获取上一个程序的最后一个参数 


    [root@base ~]# vim special_variable.sh #写入以一下内容 
    ### 插入插入以下内容
    
    #!/bin/bash  
    echo "$* 表示这个程序的所有参数 " 
    echo "$# 表示这个程序的参数个数" 
    echo "$$ 表示程序的进程 ID " 
    touch /opt/d.txt & 
    echo "$! 执行上一个后台指令的 PID" 
    echo "$$ 表示程序的进程 ID " 
    echo "$? 表示上一个程序执行返回结果 " 
    
    ### 执行结果看图

![111.png](https://s2.loli.net/2022/01/11/4XBqOz321bNmZYI.png)



```
[root@exrcise1 ~]# echo 1 2 3 4 5 6 
1 2 3 4 5 6
[root@exrcise1 ~]# echo $_
6
```



脚本传参的三种方法：

1.直接传参

```
[root@home opt]# ./a.sh 1 2 3 4 5 6
```

2.赋值传参

```
[root@home opt]# cat a.sh
#!/bin/bash
var10=123
echo $var10
```

3.交互式传参

read 命令

```
[root@home opt]# cat a.sh 
#!/bin/bash

read -p "请输入你的手机号：" a 
echo "我的手机号是：$a "
[root@home opt]# ./a.sh 
请输入你的手机号：123456789
我的手机号是：123456789 
```



## 14.数学运算

<font color='red'>expr命令 （只支持整数）</font>


操作符 | 描述
---|---
ARG1 \\| ARG2 | 如果ARG1既不是NULL也不是零值，返回ARG1,否则返回ARG2(不支持字符串) 
ARG1 \\& ARG2 | 如果没有参数是NULL或零值，返回ARG1,否则返回ARG2(不支持字符串) 
ARG1 < ARG2 | 如果ARG1小于ARG2，返回1，否则返回0
ARG1 <= ARG2 | 如果ARG1小于等于ARG2，返回1，否则返回0
ARG1 = ARG2 | 如果ARG1等于ARG2，返回1，否则返回0
ARG1 != ARG2 | 如果ARG1不等于ARG2，返回1，否则返回0
ARG1 >= ARG2 | 如果ARG1大于等于ARG2，返回1，否则返回0
ARG1 > ARG2 | 如果ARG1大于ARG2，返回1，否则返回0
ARG1 + ARG2 | 返回ARG1与ARG2的算术运算和
ARG1 - ARG2 | 返回ARG1与ARG2的算术运算差
ARG1 * ARG2 | 返回ARG1与ARG2的算术运算乘积
ARG1 / ARG2 | 返回ARG1与ARG2的算术运算商
ARG1 % ARG2 | 返回ARG1与ARG2的算术运算余数

    (1)对数字的基本计算，做比较时，输出结果假为0，1为真；特殊符号用转义符
    [root@base ~]#expr  2   \>  5
    0
    [root@base ~]#expr  6   \>  5
    1
    [root@base ~]#expr  3   *   5
    expr:语法错误
    [root@base ~]#expr  3   \*  5
    15
    [root@base ~]#expr  3   \+  5
    8
     
    (2)对字符串的处理(了解)
    [root@base ~]#expr  length  "ni hao"
    6
    [root@base ~]#expr  substr  "ni hao" 2 4    #从第2个开始，截取4个字符出来
    i   ha

---

---
## 15.使用$(())  <font color='red'>#主要用于数学运算</font>

格式：$（（表达式1，表达式2））

特点：

<font color='red'>
1、在双括号结构中，所有表达式可以像c语言一样，如：a++,b--等。a++等价于a=a+1
</font>


2、在双括号结构中，所有变量可以不加入：“$”符号前缀

3、双括号可以进行逻辑运算，四则运算

4、双括号结构扩展for，while,if条件测试运算

5、支持多个表达式运算，各个表达式之间用“，”分开

<font color='red'>
6、$(( ))=$[ ]
</font>

---


常用的算数运算符

运算符 | 意义
---|---
++， -- | 递增及递减，可前置也可以后置
+， -， !， ~ | 一元运算的正负号逻辑与取反
+， -， *， /， % | 加减乘除与余数
<<=， >>= | 比较大小符号
==，!= | 相等,不相等
>>，<<  | 向左位移，向右位移
&,^,\| | 位的与位的异或位的或
&&，\|\| | 逻辑与逻辑或
？: | 条件判断


    例 1： 
    [root@base opt]# b=$((1+2)) 
    [root@base opt]# echo $b 
    3
    [root@base opt]# echo $((2*3)) 
    6
    
    例 2：递增和递减 
    [root@base opt]# echo $((b++)) 
    4 
    [root@base opt]# echo $((++b)) 
    4
    说明： a++或 a--为先赋值再+1 或减 1 ； ++a 或--a 为先加 1 或减 1，然后再进行赋值 
    
    例 3： 求 1 到 100 的和 
    [root@base opt]# echo $((100*(1+100)/2)) 
    5050 
    
    例4： $(( ))=$[]  
    [root@home opt]# echo $((1+2))
    3
    [root@home opt]# echo $[1+2]
    3

bc 支持小数和整数运算

[root@exrcise1 yum.repos.d]# echo 1+1.5|bc
2.5
[root@exrcise1 yum.repos.d]# echo 1*1.5|bc
1.5
[root@exrcise1 yum.repos.d]# echo 1-1.5|bc
-.5



awk运算

```
[root@exrcise1 opt]# awk 'BEGIN{print 10-10}'
0
[root@exrcise1 opt]# awk 'BEGIN{print 10-15}'
-5
[root@exrcise1 opt]# awk 'BEGIN{print 10+10}'
20
[root@exrcise1 opt]# awk 'BEGIN{print 10+100/2}'
60
[root@exrcise1 opt]# awk 'BEGIN{print 10+100/2*4}'
210

```

作业：做一个计算器，执行脚本输出结果







## 16.实战-安装系统中的java1.8版本(用于环境准备)



安装jdkjava运行环境

上传jdk-8u161-linux-x64.rpm软件包到base 

    [root@base ~]#rpm   -ivh    jdk-8u161-linux-x64.rpm
    [root@base ~]#rpm   -qpl    /root/jdk-8u161-linux-x64.rpm       #通过查看jdk的信息可以知道jdk的安装目录在/usr/java


​      
​    [root@base ~]#vim   /etc/profile#在文件的最后添加以下内容：
​    export  JAVA_HOME=/usr/java/jdk1.8.0_161
​    export JRE_HOME=${JAVA_HOME}/jre
​    export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib:$CLASSPATH
​    export JAVA_PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin
​    export PATH=$PATH:${JAVA_PATH}
​    
​    [root@base ~]#source    /etc/profile#使配置文件生效
​     
​    验证java运行环境是否安装成功：
​    [root@base ~]#java  -version
​    javaversion"1.8.0_161"




---

---
**总结：**

1.Linux中默认空格为分隔符

2.单双引号要成双出现，只有一个会显示没有输入完整要你继续输入

3.cat

    cat > a.txt << EOF
    
    ctrl+d 有警告
    
    cat > a.txt
    
    ctrl+d 无警告
![error1.png](https://s2.loli.net/2022/01/11/TfFj7s4wdylRZSX.png)

4. 4个加载文件，先全局后局部

5. 变量先局部后全局，可以理解为代码块作用域，先找近的
![22.png](https://s2.loli.net/2022/01/11/e8fJ3GxnpVgkHMD.png)

6.

        $(( )) = $[ ]  
        
        $( ) = ``

7.实战：如何自定义命令

    方法1：设置别名
    alias abc='ifconfig'


​    
​    方法2：软链接命令
​    [root@master opt]# echo $PATH  #查看系统环境变量路径，当系统执行一个命令时，会去环境变量路径下寻找二进制文件
​    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin 
​    [root@master opt]# which ifconfig
​    /usr/sbin/ifconfig
​    [root@master opt]# ln -s /usr/sbin/ifconfig /usr/sbin/abc
​    [root@master opt]# abc
​    ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
​            inet 192.168.245.204  netmask 255.255.255.0  broadcast 192.168.245.255
​            inet6 fe80::d31:b56f:b04b:46fc  prefixlen 64  scopeid 0x20<link>
​            ether 00:0c:29:51:53:58  txqueuelen 1000  (Ethernet)
​            RX packets 15897  bytes 1804365 (1.7 MiB)
​            RX errors 0  dropped 0  overruns 0  frame 0
​            TX packets 7879  bytes 1121008 (1.0 MiB)
​            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


​    
​    方法3：修改系统环境变量
​    [root@master opt]# cp /usr/sbin/ifconfig /opt/abc
​    [root@master opt]# vim /etc/profile
​    在最后一行添加：
​    export PATH=$PATH:/opt
​    [root@master opt]# source  /etc/profile        #刷新系统环境变量
​    [root@master opt]# echo $PATH                    
​    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/opt
​    [root@master opt]# abc
​    ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
​            inet 192.168.245.204  netmask 255.255.255.0  broadcast 192.168.245.255
​            inet6 fe80::d31:b56f:b04b:46fc  prefixlen 64  scopeid 0x20<link>
​            ether 00:0c:29:51:53:58  txqueuelen 1000  (Ethernet)
​            RX packets 15897  bytes 1804365 (1.7 MiB)
​            RX errors 0  dropped 0  overruns 0  frame 0
​            TX packets 7879  bytes 1121008 (1.0 MiB)
​            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

 


---
source 脚本   ==> 这样的启动方式也可以

执行脚本会产生一个子进程