*一、Shell变量概述

1.什么是变量

变量其实是Shell传递数据的⼀种⽅式。以⼀个固定的字符串去表示⼀个不固定的值。便于后
续的复⽤,以及维护。

2.变量的命名规范 ( 熟悉 )

变量命令规范:⼤⼩写、下划线拼接变量名、尽量字⺟开头。( 变量最好有含义,如果没
有,容易忘记这个变量是做什么的。 )
变量如何定义: 变量名=变量值,等号是赋值。 a=123 a变量 123值

3.变量定义参考:

HostnameIp=10.0.0.1 #驼峰式命名 ⼤写开头⼩写结束⼤写开头_⼩写结束
# ‘变量名称’ ⾸字⺟⼤写的原因是为了避免与系统的命令产⽣冲突。


二、变量定义的方式

2.1 ⽤户⾃定义变量

———⾃⼰随意定义变量。

Ps : shell脚本中 AWK命令如何 使用变量

  1. result=$(awk -v free=${free} 'BEGIN {print free / 1024 }')

[root@web01 ~]# var=”hello world” #定义变量 ( 等号两边没有空格 )
[root@web01 ~]# echo $var #$变量名 ${变量名}
hello world

使⽤$变量名 ${变量名} 区别?
[root@web01 ~]# echo $var_log
[root@web01 ~]# echo ${var}_log
hello world_log

单引号和双引号的区别?
[root@web01 ~]# var2=Iphone
[root@web01 ~]# echo “$var2 is good” #双引号会解析中的$符号
Iphone is good
[root@web01 ~]# echo ‘$var2 is good’ #写什么就是什么
$var2 is good

什么时候使⽤ 单引号和双引号:
“ “ 弱引用 如果你输出的结果中包含变量名需要解析,则建议使⽤双引号。
‘ ‘ 强引用 如果你输出的结果仅仅只是⼀个字符串,但⾥⾯存在特殊字符,那么你可以选择使⽤单引号。

2.2 系统环境变量

—-保存的是和系统操作环境相关的#系统已经定义好了⼀些个变量,所有⽤户都可以调⽤。

[root@web01 ~]# cat check_env.sh

  1. #!/bin/bash
  2. echo "⽤户的家⽬录: $HOME"
  3. echo "当前主机名是: $HOSTNAME"
  4. echo "当前所在⽬录: $PWD"
  5. echo "当前SSH连接: $SSH_CONNECTION"

[root@web01 ~]# cat get_system_info.sh

  1. #!/bin/bash
  2. #如果执⾏该脚本的UID不为0,则提示没有权限,如果为0 则输出系统状态指标获取成功。 [
  3. -ne 表示不等于 ]
  4. if [ $UID -ne 0 ];then echo "$USER 没有权限执⾏该脚本!!"
  5. exit
  6. fi
  7. echo "系统状态指标获取完毕!!!"
  8. #拷⻉到其他普通⽤户测试

[root@web01 ~]# useradd oldg
[root@web01 ~]# cp get_system_info.sh /home/oldg/
[root@web01 ~]# su - oldg
[oldg@web01 ~]$ sh get_system_info.sh
oldg 没有权限执⾏该脚本!!

2.3 位置参数变量

——-向脚本进⾏传递参数的,变量名不能⾃定义,变量作⽤也是固定的。
[root@web01 ~]# cat variables.sh

#!/bin/bash

echo "#当前shell脚本的⽂件名: $0"
echo "#第1个shell脚本位置参数:$1"
echo "#第2个shell脚本位置参数:$2"
echo "#第3个shell脚本位置参数:$3"

echo "#所有传递的位置参数是: $*"
echo "#所有传递的位置参数是: $@"
echo "#总共传递的参数个数是: $#"
echo "#当前程序运⾏的 PID 是: $$"
echo "#上⼀个命令执⾏的返回结果: $?"

[root@web01 ~]# sh variables.sh 11 22 33 44

#当前shell脚本的⽂件名: variables.sh
#第1个shell脚本位置参数:11
#第2个shell脚本位置参数:22
#第3个shell脚本位置参数:33
#所有传递的位置参数是: 11 22 33 44
#所有传递的位置参数是: 11 22 33 44
#总共传递的参数个数是: 4
#当前程序运⾏的 PID 是: 4159
#上⼀个命令执⾏的返回结果: 0

4.练习需求:通过位置变量创建 Linux 系统账户及密码,执⾏ var1.sh username password
[root@web01 ~]# cat create_user_1.sh

#!/bin/bash

#1.添加⽤户
useradd $1

#为⽤户设定密码
echo "$2" | passwd --stdin $1
[root@web01 ~]# sh create_user_1.sh oldxxx 123

综合练习
需求: 通过位置变量创建 Linux 系统账户及密码,执⾏ var1.sh username password,控制最多传递两个参数。【这个脚本仅root能执⾏,其他普通⽤户⽆法执⾏创建⽤户脚本。】

思路:

#1.如何知道他传递了多少个参数?                     $#
#2.判断他传递的参数是否⼤于我想设定的参数? if
⼤于:则报错提示
刚好:执⾏脚本

[root@web01 ~]# cat create_user_2.sh

#!/bin/bash
##############################################################
# File Name: create_user_1.sh
# Author: oldxu
# Organization: 552408925@qq.com
##############################################################
#1.判断他是什么⽤户身份在执⾏这个脚本
if [ $UID -ne 0 ];then
echo "$USER ⽤户你没有权限,请切到Root⽤户在执⾏"
exit
fi
#2.判断⽤户传递的的参数是否满⾜2个
if [ $# -ne 2 ];then
echo "Please Input Parameters [ username && password ]"
exit
fi

#3.添加⽤户
useradd $1#4.为⽤户设定密码
echo "$2" | passwd --stdin $1

2.4 变量赋值的方式read

(交互式传递变量)
image.png
[root@web01 ~]# cat read-1.sh

#!/bin/bash
##############################################################
# File Name: read-1.sh
# Author: oldxu
# Organization: 552408925@qq.com
##############################################################
read -p "Login: " acc
read -p "Passwd: " pw
echo "login: $acc passwd: $pw"

[root@web01 ~]# cat read-1.sh

#!/bin/bash
##############################################################
# File Name: read-1.sh
# Author: oldxu
# Organization: 552408925@qq.com
##############################################################
read -p "Login: " acc
read -s -t10 -n6 -p "Passwd: " pw
echo "login: $acc passwd: $pw"


read练习题

需求1: 使⽤read模拟Linux登陆⻚⾯
#1.你先得知道linux的登陆⻚⾯是啥样⼦的?
4.png
[root@web01 ~]# cat read-2.sh

#!/bin/bash
##############################################################
# File Name: read-2.sh
# Author: oldxu
# Organization: 552408925@qq.com
##############################################################
hostnamectl | awk -F ':' '/System/ {print $2}'
echo "Kernel $(uname -r) an $(uname -m)"
echo ""
read -p "$(hostname) login: " acc
read -s -p "Passwd: " pw
echo ""
echo "Login: $acc Passwd: $pw"

需求2: 使⽤ read编写⼀个备份脚本,需要⽤户传递2个参数,源和⽬标。

1.在执⾏脚本时,
提示1:请填写需要备份的⽂件或⽬录路径: /opt
提示2:你希望备份到哪去: /tmp

action动作:
cp -rp /opt/ /tmp
[root@web01 ~]# cat read-3.sh

#!/bin/bash
##############################################################
# File Name: read-3.sh
# Author: oldxu
# Organization: 552408925@qq.com
##############################################################
read -p "你要备份的⽂件或⽬录路径是: " src
read -p "你要备份到哪个⽬录下存储:" dest
read -p "你确定将 $src 备份到 $dest 吗? [ y | n ]" action
#判断⽤户输⼊的是y还是n,y则进⾏备份,n则提示没有备份
if [ $action == "y" ];then
echo "-----------备份开始--------------"
cp -rp $src $dest
sleep 3
echo "-----------备份结束--------------"
else echo "-----------备份退出--------------"
exit
fi

需求3: 使⽤ read编写⼀个探测主机存活脚本,需要⽤户传递测试的IP地址。
[并没有说使⽤传参,⽽是让其使⽤read的⽅式]
[root@web01 ~]# cat read-4.sh

#!/bin/bash
##############################################################
# File Name: read-4.sh
# Author: oldxu
# Organization: 552408925@qq.com
##############################################################
#探测主机是否存活
read -p "请输⼊你要探测的主机IP地址: " Ip
ping -c2 $Ip &>/dev/null
if [ $? -eq 0 ];then
echo "$Ip 存活"
else
echo "$Ip 不存活"
fi

需求4:使⽤read编写⼀个修改系统主机名称脚本。【询问:是否修改,y修改、n退出脚本不修改】
[root@web01 ~]# cat read-5.sh

#!/bin/bash

# 思路
#脚本⼤概内容应该如下:
#1.先输出当前系统的主机名称: web01
#2.询问需要修改为新的主机名称是什么? test01
#3.确定要将 web01 变更为 test01 吗? [ y | n ]
#4.判断⽤户输⼊的是y还是n
#y:使⽤hostnamectl 变更主机名称
#n:直接退出此脚本

Old_Host=$(hostname)
echo "当前系统的主机名称是: ${Old_Host}"
read -p "你想修改的主机名称是: " New_Host
read -p "你确定要将 ${Old_Host} 变更为 ${New_Host} 名称吗? [ y | n ]" Actionif [ $Action == "y" ];then
echo "------------------正在修改主机名称-------------------"
hostnamectl set-hostname ${New_Host}
sleep 1
echo ""
echo "-----------------主机名称修改完毕---------------------"
fi

*三、变量的替换

在不改变原来变量的值情况下,进⾏变量的替换。( 双符号: 贪婪匹配模式 )
image.png

#和双

[root@web01 ~]# url=www.sina.com.cn
[root@web01 ~]# echo ${url}
www.sina.com.cn
[root@web01 ~]# echo ${url#*.} #从头开始匹配,然后删除
sina.com.cn

[root@web01 ~]# echo ${url#..}
com.cn

[root@web01 ~]# echo ${url##*.} #贪恋匹配模式
cn

%和双%%

[root@web01 ~]# echo ${url%.*}
www.sina.com

[root@web01 ~]# echo ${url%..}
www.sina

[root@web01 ~]# echo ${url%%.*}
www

/ 和双 //

[root@web01 ~]# echo ${url}
www.sina.com.cn

[root@web01 ~]# echo ${url/sina/SINA} 只会替换匹配到的第一个
www.SINA.com.cn

[root@web01 ~]# echo ${url//c/C} #匹配到的所有的都替换
www.sina.Com.Cn

练习1.希望把$PATH中的/bin全部都替换为 /BIN
[root@web01 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@web01 ~]# echo ${PATH//bin/BIN}
/usr/local/sBIN:/usr/local/BIN:/usr/sBIN:/usr/BIN:/root/BIN

习题1:
需求2:变量string=”Bigdata process is Hadoop, Hadoop is open source

project",执⾏脚本后,打印输出string变量,并给出⽤户以下选项:
1)、打印string⻓度
2)、删除字符串中所有的Hadoop                           # echo  $ {xxx//内容/空}
3)、替换第⼀个Hadoop为Linux
4)、替换全部Hadoop为Linux
⽤户输⼊数字1|2|3|4,可以执⾏对应项的功能,输⼊q|Q则退出交互模式

[root@web01 ~]# cat vars.sh

#!/bin/bash

string="Bigdata process is Hadoop, Hadoop is open source project"
echo "$string"
cat <<EOF
1)、打印string⻓度
2)、删除字符串中所有的Hadoop
3)、替换第⼀个Hadoop为Linux
4)、替换全部Hadoop为Linux
EOF
read -p "请输⼊你想执⾏的操作 [ 1 | 2 | 3 | 4 | q ] " Action
if [ $Action -eq 1 ];then
echo "String变量的⻓度是: ${#string}"
fi
if [ $Action -eq 2 ];then
echo ${string//Hadoop/}
fi
if [ $Action -eq 3 ];then
echo ${string/Hadoop/Linux}
fi
if [ $Action -eq 4 ];then
echo ${string//Hadoop/Linux}
fi

Ps: 可以使用case完成

习题2:
查看内存/当前使⽤状态,如果使⽤率超过80%则报警发邮件
思路:
1.如何查看内存整体情况 free -m
2.如何查看内存的百分⽐ free -m | awk ‘/^Mem/ {print $3/$2*100}’
3.设定的阈值与已使⽤量进⾏⽐对 80 是⼤于 已使⽤,还是⼩于已使⽤
⼤于 则报警
⼩于 则不管
[root@web01 ~]# cat check_memory.sh

#!/bin/bash

Mem_Use=$(free -m | awk '/^Mem/ {print $3/$2*100}')
if [ ${Mem_Use%.*} -ge 80 ];then
echo "内存已经超过所设定的阈值,请尽快处理,当前已使⽤内存为 ${Mem_Use}
"
else
echo "内存当前状态良好,当前已使⽤内存为 ${Mem_Use%.*}%"
fi

四、变量的运算

1.什么是变量运算? + - x /

2.为什么要学习呢?

3.shell使⽤什么⽅式来实现变量的运算呢?

$(( ))
$[ ]
#$( )命令 ${ }变量

4.bc、awk ⼩数运算
% 余数如果为0,说明两者之间整除

[root@web01 ~]# num1=10
[root@web01 ~]# num2=20
[root@web01 ~]#
[root@web01 ~]# expr $num1 + $num2
30
[root@web01 ~]#
[root@web01 ~]# echo $(( $num1 + $num2 ))
30
[root@web01 ~]# echo $[ $num1 + $num2 ]
30
[root@web01 ~]# echo $[ $num1 - $num2 ]
-10
[root@web01 ~]# echo $[ $num1 * $num2 ]
200
[root@web01 ~]# echo $[ $num1 / $num2 ]
0

1.根据系统的时间,打印今年和明年时间。2020 2021 date +%Y

[root@web01 ~]# echo "This is $(date +%Y) year"
This is 2020 year
[root@web01 ~]# echo "This is $(( $(date +%Y) +1 )) year"
This is 2021 year

2.根据系统时间获取今年还剩下多少个星期,已经过了多少个星期。

[root@web01 ~]# cat vars-2.sh

#!/bin/bash
#1.获取今年是⼀年中的第多少天? date +%j
#2.通过获取已过的天数,/7 就能得到已经过了多少周了。
#3.通过(365 - 100)/7 还剩下多少周。

echo "今年已经过了 $(date +%j) days"
echo "记你已经过了 $(( $(date +%j) /7 )) weeks"
echo "距离新年还剩多少周 $(( ( 365 - $(date +%j) ) /7 )) weeks"

3.完成⼀个 “简单” 的计算机功能,
[root@web01 ~]# cat vars-3.sh

#!/bin/bash
通过read⽅式传⼊2个值【⽽不是传参的⽅式】,进⾏ 加、
减、乘、除:
1.read传递两个值
2.将传递的两个值,分别使⽤两个变量进⾏接收
3.对两个变量进⾏加减乘除。

read -p "请输⼊要计算的第⼀个数字: " num1
read -p "请输⼊要计算的第⼆个数字: " num2
echo "$num1 + $num2 = $(( $num1 + $num2 ))"
echo "$num1 - $num2 = $(( $num1 - $num2 ))"
echo "$num1 * $num2 = $(( $num1 * $num2 ))"

五、今日总结&作业

总结:
1.简单介绍了Shell、Shell脚本、使⽤场景( 备份、监控、字符处理、等 )、
2.shell规范、学习shell的要求(基础命令)、shell执⾏⽅式 #!/usr/bin/bash、Shell命名有要求 (⽣产环境)
3.Shell变量。
1.变量命令规则、定义、使⽤、
2.⽤户如何⾃定义变量、环境变量、预定义变量。 $1 $2 $0 $# $? $ $@
3.read交互的⽅式传递参数【只要牵扯到要交互,则使⽤read,如果⽆需交互,直接传参 $1 $2 】
4.shell变量替换、删除。
5.shell整数运算。
6.作业练习题-所有脚本⾃⼰都写⼀遍

练习:*

需求1 使⽤Shell脚本打印,系统版本、内核版本平台、虚拟平台、静态主机名、eth0⽹卡IP地址、 lo⽹卡IP地址、当前主机的外⽹IP地址curl icanhazip.com
思路:1取值:hosnamectl uanme -r awk 在使用free -m 取值 运算

#!/bin/bash
#取值
Osversion=$(hostnamectl |awk -F "[ :]+" 'NF==7{print $6}')
Kernel=$(hostnamectl | awk -F '[ :]+' 'NR==9{print $3,$4}')
Paas=$(hostnamectl | awk -F '[ :]+' 'NR==6{print $3}')
Hosname=$(hostname)
Eht0Ip=$(ifconfig  eth0 | sed  -rn  's#^.*inet (.*) net.*$#\1#gp')
LoIp=$(ifconfig  lo | sed  -rn  's#^.*inet (.*) net.*$#\1#gp')
UrlIP=$(curl icanhazip.com) #-s 静默输出

#打印
echo "您当前系统版本          :${Osversion}"
echo "您当前系统内核品台      :${Kernel}"
echo "您当前系统虚拟平台      :${Paas}"
echo "您当前系统静态主机名    :${Hosname}"
echo "您当前系统eth0网卡地址  :${Eht0Ip} "
echo "您当前系统lo网卡地址    :${LoIp}"
echo "icanhazip.com 的ip地址  :${UrlIP}"


2:查看系统当前有几个登陆的用户。

#!/bin/bash

#取值
Login=$(who |wc -l)

#输出
echo "当前登录用户用户为: ${Login}个"

3.查看当前系统已使⽤磁盘的百分⽐。
df -h 取值

#!/bin/bash
#取值
Used=$(df | grep '/$'| awk '{print $(NF-1)}')
#输出
echo "当前系统磁盘使用率为: ${Used}"

4 查看当前系统已使⽤内存的百分⽐。

#!/bin/bash
#取值
Free=$(free -m | awk  '/Mem/{print $3/$4*100}')
#输出
echo "当前系统磁盘使用率为: ${Free}%"

5.写个shell,看看你的linux系统中是否有⾃定义⽤户(普通⽤户),若是有,⼀共有⼏个?。

#!/bin/bash
#取值
Users=$(awk -F ":" '$3>1000{print $1}' /etc/passwd |wc -l)
User=$(awk -F ":" '$3>1000{print $1}' /etc/passwd)

#输出
echo "当前系统中有 ${Users} 个自定义用户 "
echo "当前系统中自定义用户为: "
echo "${User}"


  1. 通过为止变量创建用户 ```bash

    /usr/bin/bash

1.添加⽤户

useradd $1

为⽤户设定密码

echo “$2” | passwd —stdin $1



7.取出当前系统⽇期、时间、当前有⼏个登陆⽤户、过去_15_分钟的平均负载、当前可⽤内存⼤⼩、当前系统空闲时间,输⼊到_/tmp/txt.csv_。<br />取值<br />执行重定向命令
```bash
#!/bin/bash
#取值
Date=$(date +%F)
Time=$(date +%T)
Login=$(who |wc -l)
Uptime=$(cat /proc/uptime)
Free=$(free -m | awk  '/Mem/{print $3/$4*100}')
Free1=$(free -m | awk  '/Mem/{print $3}')
Statusone=$(uptime |awk -F '[ ,]+' '{print $NF}')
Statusfive=$(uptime |awk -F '[ ,]+' '{print $(NF-1)}')
Statusfifteen=$(uptime |awk -F '[ ,]+' '{print $(NF-2)}')

#打印并输出到日志
cat  <<EOF |tee  /tmp/txt.csv
当前系统日期          :  $Date  
当前系统时间          :  $Time 
当前系统登录用户个数  :  $Login 
当前系统负载          :  $Statusone $Statusfive $Statusfifteen
当前系统可用内存大小  :  ${Free}% ( ${Free1}M )
当前系统空闲时间      :  $Uptime
EOF


已解决的问题:**

if [ ];then # [ ]括号内容两边都需要空格 fi

replace_test.sh:行33: ${ string//Hadoop/Linux }: 坏的替换
${string//Hadoop/Linux } 变量内容不能出行空格

脚本提示不是有效的标识符:
本章内容 -s 要写在最前面。

取值错误: wak -F “ “ ‘ / / {print } ‘
awk取值使用强引号