Shell脚本变量
Shell脚本变量
1.Shell变量概述
1.什么是变量
变量是Shell
传递数据的一种方法,简单理解:就是一个固定的字符串区表示不固定的值,便于后续引用。
2.变量命令规范
变量定义时名称有要求:字母、数字、下划线组成,尽量字母开头,{变量名最好具备一定的含义}
ip=10.0.0.100
ip1=10.0.0.100
Hostname_Ip=10.0.0.100
hostname_IP=10.0.0.100
等号是赋值,需要注意:等号两边不能有空格,其次定义的变量不要与系统命令出现冲突。
1.变量的定义,需要具备一定的含义,同时不要与系统的命令产生冲突。
HostName_IP
HostName_Network
2.定义变量示例
[root@zxm ~]# HostName=$(hostname)
[root@zxm ~]# echo $HostName
zxm
3.错误定义变量方式
[root@zxm ~]# HostName = $(hostname) //不能有空格
自定义变量练习
[root@zxm ~]# var="hello shell"
[root@zxm ~]# echo $var
hello shell
[root@zxm ~]# echo $var_log #$var_log当做一个整体
[root@zxm ~]# echo ${var}_log
hello shell_log
3.shell变量定义的方式
- 用户自定义变量:人为定义变量名称;
- 系统环境变量:保存的是和系统操作环境相关的数据;
- 位置参数变量:向脚本中进行参数传递,变量名不能自定义,变量作用是固定的。
- 预定义的变量:是
Bash
中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
4.shell变量定义实践
1.用户自定义变量示例,当前shell
有效
#1)定义变量,变量名=变量值。不能出现“-”命名
[root@backup ~]# var="hello zxm" #定义变量有空格必须使用双引号
#2)引用变量,$变量名或者${变量名}
[root@backup ~]# echo $var
hello zxm
[root@backup ~]# echo ${var}
hello zxm
[root@backup ~]# echo ${var}_log
hello_zxm_log
#3)查看变量,set显示所有变量,包括自定义变量和环境变量
[root@backup ~]# set |grep var
var=hello_zxm
#4)取消变量,作用范围:仅在当前shell中有效
[root@backup ~]# unset var
#5)注意事项,引用变量时注意 “” 双引号属于弱引用, ''单号输入强引用
[root@backup ~]# var=zxm
[root@backup ~]# echo $var
zxm
[root@backup ~]# echo "$var is good person"
zxm is good person
[root@backup ~]# echo '$var is good person'
$var is good person
1.在定义变量的时候,比如: var="$(hostname)"
2.在引用变量的时候,尽可能的使用双引号 echo "$var"
3.在我们使用echo输出的时候,如果输出的字符串中有特殊的符号,建议使用单引号 echo '#$123'
[root@zxm ~]# echo "$var is good is \$500"
希望$var被解析
而$500 不被解析
2.系统环境变量示例,在当前shell
和子shell
有效
#1)定义环境变量:export 变量,将自定义变量转换成环境变量
[root@zxm shell]# var2=hello
[root@zxm shell]# echo $var2
hello
[root@zxm shell]# cat a.sh
#!/bin/bash
echo $var2
[root@zxm shell]# sh a.sh #执行a.sh 时,会使用另一个bash去执行,就访问不到$VAR1的值
[root@zxm shell]# export var2=hello #将变量转为环境变量
[root@zxm shell]# sh a.sh #再次执行脚本
hello
#2)使用系统已定义好的环境变量
[root@backup shell]# cat env.sh
#!/bin/bash
echo "用户的家目录: $HOME"
echo "当前主机名是: $HOSTNAME"
echo "当前所在目录: $PWD"
[root@backup shell]# sh env.sh
用户的家目录: /root
当前主机名是: backup
当前所在目录: /scripts/shell
3.预先定义的变量参数示例,系统内置变量的使用方法。
#1.脚本如下
[root@zxm shell]# cat variable.sh
#!/bin/bash
echo "#当前shell脚本的文件名: $0"
echo "#第1个shell脚本位置参数:$1"
echo "#第2个shell脚本位置参数:$2"
echo "#第3个shell脚本位置参数:$3"
echo "#所有传递的位置参数是: $*"
echo "#所有传递的位置参数是: $@"
echo "#总共传递的参数个数是: $#"
echo "#当前程序运行的 PID 是: $$"
echo "#上一个命令执行的返回结果: $?"
#2.执行结果如下
[root@backup shell]# sh variable.sh 11 22 33 44 55 66
#当前shell脚本的文件名: variable.sh
#第1个shell脚本位置参数:11
#第2个shell脚本位置参数:22
#第3个shell脚本位置参数:33
#所有传递的位置参数是: 11 22 33 44 55 66
#所有传递的位置参数是: 11 22 33 44 55 66
#总共传递的参数个数是: 6
#当前程序运行的 PID 是: 49194
#上一个命令执行的返回结果: 0
需要注意的是: shell $*
与$@
的区别
[root@zxm shell]# cat tt.sh
#! /bin/bash
test() {
echo "未加引号,二者相同"
echo $*
echo $@
echo "加入引号后对比"
echo "----"\$*----""
for N in "$*"
do
echo $N
done
echo "----"\$@----""
for N in "$@"
do
echo $N
done
}
test 11 22 33
执行后结果如下
[root@zxm shell]# sh tt.sh
未加引号,二者相同
11 22 33
11 22 33
加入引号后对比
----$*----
11 22 33
----$@----
11
22
33
可以看到不加引号时,二者都是返回传入的参数,但加了引号后,此时\(\*把参数作为一个字符串整体(单字符串)返回,\)@把每个参数作为一个字符串返回
4.补充:将命令执行的结果传递给变量(命令替换)
#根据系统时间,打印几年时间和明年时间
[root@zxm shell]# echo "This is $(date +%Y) year"
This is 2019 year
[root@zxm shell]# echo "This is $(($(date +%Y)+1)) year"
This is 2020 year
#命令的嵌套使用,使用$( $( ) )
[root@backup shell]# find /root/ -name *.txt
[root@backup shell]# db=$(tar czvf root.tar.gz $(find /root/ -name *.txt))
[root@backup shell]# echo $db
2.Shell变量赋值
除了自定义变量,以及系统内置变量,还可以使用read
命令通过交互方式传递变量
1.read示例语法
[root@backup scripts]# cat read1.sh
#!/bin/bash
read -p "请输入你要备份的目录:" varsfile
echo "你要备份的目录是:" $varsfile
执行效果:
[root@backup scripts]# sh read1.sh
请输入你要备份的目录:/etc //ctrl+u 可以清掉输出错误的信息
你要备份的目录是: /etc
2.read示例语法,简单备份场景
[root@backup scripts]# cat read2.sh
#!/bin/bash
back_dir1=/var/backup
read -p "请输入您的备份目录:" back_dir2
echo $back_dir1
echo $back_dir2
执行效果:
[root@backup scripts]# sh read2.sh
请输入您的备份目录:/etc
/var/backup
/etc
3.read示例语法,测试用户输入的IP是否通
- 执行脚本时,提示:请输入ip;
- 使用ping命令去探测是否是通,如果是通的则返回GG,不同则返回NG;
if 语法
if [];then
else
fi
[root@backup scripts]# cat read3.sh
#!/bin/bash
#1.提示用户输入一个IP地址
read -p "请输入您的ip:" ip
echo "您输入的ip是:" $ip
#2.使用ping命令检测IP地址是否通讯
ping -W1 -c3 $ip &>/dev/null
rc=$? //将$?的0或非0的值赋给了rc,防止ping命令之后其他操作导致$?的值发生改变
if [ $rc == 0 ] ; then
echo "$ip 能正常通信。"
else
echo "$ip 不能正常通信。"
fi
4.使用read命令写一个脚本修改主机名和IP地址
- 提示用户输入主机名称;
- 提示用户输入IP地址;
- 询问用户是否确认此操作;
- 执行;
[root@backup scripts]# cat read4.sh
#!/bin/bash
read -p "请输入主机名称:" HostName
read -p "请输入主机ip:" IP
read -p "Are you sure!(yes/no):" var1
if [ $var1 == "yes" ];then
#修改主机名
hostnamectl set-hostname $HostName
#获取本机ip
IP1=$(ifconfig eth1 | awk 'NR==2{print $2}')
#修改IP地址
sed -i "s/IPADDR=$IP1/IPADDR=$IP/" /etc/sysconfig/network-scripts/ifcfg-eth1
#重启网卡
systemctl restart network
else
exit
fi
3.Shell变量替换
变量 | 说明 |
---|---|
$ | 从头开始匹配,最短删除 |
$ | 从头开始匹配,最长删除 |
$ | 从尾开始匹配,最短删除 |
$ | 从尾开始匹配,最长删除 |
$ | 替换变量内的旧字符串为新字符串,只替换第一个 |
$ | 替换变量内的旧字符串为新字符串,全部替换 |
1.从前往后删除变量内容
[root@backup ~]# qq=123456789
[root@backup ~]# echo ${qq} //输出变量的值
123456789
[root@backup ~]# echo ${qq#*3} //从头开始匹配,删除最短,保留最长的
456789
[root@backup ~]# echo ${qq##*7} //从头开始匹配,删除最长,保留最短的
89
2.从后往前删除变量内容
[root@backup ~]# echo ${qq} //输出变量的值
123456789
[root@backup ~]# echo ${qq%7*}
123456
[root@backup ~]# echo ${qq%3*}
12
3.变量内容替换
[root@backup ~]# qq=11223344
[root@backup ~]# echo ${qq}
11223344
[root@backup ~]# echo ${qq/3/4}
11224344
[root@backup ~]# echo ${qq//3/4}
11224444
【shell练习题-1】
1.查看内存/当前使用状态,如果使用率超过80%
则报警发邮件
查看内存:free -m
[root@backup ~]# free -m
total used free shared buff/cache available
Mem: 3770 242 3069 43 458 3267
Swap: 2047 0 2047
使用awk过滤Mem行
[root@backup ~]# free -m |awk '/^Mem/'
Mem: 3770 242 3069 43 458 3268
查看内存百分比: 使用的/总的*100%=
[root@backup ~]# free -m |awk '/^Mem/ {print $3/$2*100}'
6.4191
[root@backup scripts]# cat free_use.sh
#!/bin/bash
free_use=$(free -m |awk '/^Mem/ {print $3/$2*100}')
echo ${free_use%.*}%
if [ ${free_use%.*} -gt 80 ];then
mail -s "内存超过了80%" xxxx@qq.com
else
exit
fi
2.场景实践,在/backup下创建10个.txt的文件,找到/backup目录下所有后缀名为.txt的文件
1)批量修改txt为txt.bak
2)把所有的.bak文件打包压缩为123.tar.gz
3)批量还原文件的名字,及把增加的.bak再删除
[root@backup ~]# mkdir /backup
[root@backup ~]# mkdir /backup/{1..10}.txt
[root@backup ~]# find /backup/ -name "*.txt"
[root@backup ~]# cat rename.sh
#!/bin/bash
#将txt批量修改为txt.bak
find /backup/ -name "*.txt" |sed -r 's#(.*)#mv \1 \1.bak#g' |bash
#打包
tar czf /backup/123.tar.gz $(find /backup/ -iname "*.bak")
#还原名字
find /backup/ -name "*.bak"|sed -r 's#(.*).bak#mv \1.bak \1#g' |bash
[root@backup ~]# tar tf /backup/123.tar.gz
backup/1.txt.bak
backup/2.txt.bak
backup/3.txt.bak
backup/4.txt.bak
backup/5.txt.bak
backup/6.txt.bak
backup/7.txt.bak
backup/8.txt.bak
backup/9.txt.bak
backup/10.txt.bak
#变量替换方式
#!/usr/bin/bash
File_txt=$(find /backup/ -type f -iname "*.txt"|xargs >/backup/txt.tt)
for i in $(cat /backup/txt.tt)
do
mv $i $i.bak
done
tar czf /backup/123.tar.gz ./*.bak
File_bak=$(find /backup/ -type f -iname "*.bak" >/backup/tar.tt)
for j in $(cat /backup/tar.tt)
do
mv $j ${j%.*}
done
#rename命令
#!/bin/bash
#定义变量
T=txt
B=bak
#把backup目录下.txt结尾的文件修改成txt.bak
cd /backup && rename $T $T\.$B *.txt
#把所有的.bak结尾的文件打包压缩为123.tar.gz
tar zcvf /backup/123.tar.gz /backup/*.bak
#还原文件的名字
rename $T\.$B $T *
【shell练习题-2】
1.用shell或者python编写一个脚本,要求如下:
在每个月第一天备份并压缩/etc
目录下的所有内容,存放在/root/bak
目录里面,且文件名为如下形式yymmdd_etc
,yy为年,mm为月,dd为日。脚本名称为fileback
存放在root
的家目录下。
[root@backup ~]# cat fireback
#!/bin/bash
#声明变量
Dest=/root/bak
Date=$(date +%Y%m%d)
#判断存放目录是否存在
[ ! -d $Dest ] && mkdir -p $Dest
#备份
tar czf $Dest/${Date}_etc.tar.gz /etc
[root@backup ~]# crontab -e
00 23 1 * * bash /root/fireback
4.Shell变量运算
1.整数运算,expr
$(())
%[]
,不支持小数运算
操作符 | 含义 |
---|---|
num1 + num2 | 求和 |
num1 - num2 | 求差 |
num1 * num2 | 求积 |
num1 / num2 | 求商 |
num1 % num2 | 求余 |
#定义变量,使用expr、$(())、%[]进行加减乘除。expr必须空格隔开。
[root@backup ~]# num1=5
[root@backup ~]# num2=2
----------------------------------------------------expr---------------------------------------------------------------
[root@backup ~]# expr num1 + num2
[root@backup ~]# expr $num1 + $num2
7
[root@backup ~]# expr $num1 - $num2
3
[root@backup ~]# expr $num1 / $num2
2
[root@backup ~]# expr $num1 % $num2
1
[root@backup ~]# expr $num1 \* $num2
10
---------------------------------------------------$(())---------------------------------------------------------------
[root@backup ~]# echo $(($num1 + $num2))
7
[root@backup ~]# echo $(($num1 - $num2))
3
[root@backup ~]# echo $(($num1 / $num2))
2
[root@backup ~]# echo $(($num1 % $num2))
1
[root@backup ~]# echo $(($num1 * $num2))
10
---------------------------------------------------%[]-----------------------------------------------------------------
[root@backup ~]# echo $[$num1+$num2]
7
[root@backup ~]# echo $[$num1-$num2]
3
[root@backup ~]# echo $[$num1/$num2]
2
[root@backup ~]# echo $[$num1*$num2]
10
[root@backup ~]# echo $[$num1%$num2]
1
2.小数运算bc
,用的不是很多,了解即可
[root@backup ~]# yum install bc -y
[root@backup ~]# echo '2*4' |bc
8
[root@backup ~]# echo "2^4" |bc
16
[root@backup ~]# echo "scale=2;6/4" |bc #取2位小数
1.50
[root@backup ~]# awk 'BEGIN{print 1/2}'
0.5
5.Shell变量案例
1.使用Shell脚本打印,系统版本、内核版本平台、虚拟平台、静态主机名、eth0网卡IP地址、lo网卡IP地址
当前主机的外网IP地址curl icanhazip.com
[root@backup scripts]# cat 5.sh
#!/bin/bash
#系统版本
System=$(hostnamectl |awk 'NR==7{print $3,$4,$5,$6}')
#内核版本平台
Kernel=$(hostnamectl |awk 'NR==9{print $3}')
#虚拟平台
Virtualization=$(hostnamectl |grep Virtualization |awk '{print $2}')
#静态主机名
Statichostname=$(hostnamectl |awk 'NR==1{print $3}')
#eth0网卡的IP地址
Eth0=$(ifconfig eth0|awk 'NR==2 {print $2}')
#LO网卡的IP地址
Lo=$(ifconfig lo|awk 'NR==2 {print $2}')
#当前主机的外网ip地址
Network_T=$(curl -s icanhazip.com)
echo "系统版本是:" $System
echo "内核版本平台:" $Kernel
echo "虚拟平台:" $Virtualization
echo "静态主机名:" $Statichostname
echo "eth0网卡的IP地址:" $Eth0
echo "LO网卡的IP地址:" $Lo
echo "当前主机的外网ip地址:" $Network_T
[root@backup scripts]# sh 5.sh
系统版本是: CentOS Linux 7 (Core)
内核版本平台: 3.10.0-1160.11.1.el7.x86_64
虚拟平台: vmware
静态主机名: backup
eth0网卡的IP地址: 10.0.0.41
LO网卡的IP地址: 127.0.0.1
当前主机的外网ip地址: 120.204.78.23
2.需求描述:变量string="Bigdata process is Hadoop, Hadoop is open source project",执行脚本后,打印输出string字符串变量,并给出用户以下选项:
1)、打印string长度
2)、删除字符串中所有的Hadoop
3)、替换第一个Hadoop为Linux
4)、替换全部Hadoop为Linux
用户输入数字1|2|3|4,可以执行对应项的功能,输入q|Q则退出交互模式
[root@backup scripts]# cat 6.sh
#!/bin/bash
string="Bigdata process is Hadoop, Hadoop is open source project"
echo $string
echo "-------------------------------------------"
echo "-------------------选项--------------------"
echo "-----------1.打印string长度----------------"
echo "-----------2.删除字符串中所有的Hadoop------"
echo "-----------3.替换第一个Hadoop为Linux-------"
echo "-----------4.替换全部Hadoop为Linux---------"
echo "-------------------------------------------"
read -p "输入数字1|2|3|4,可以执行对应项的功能,输入q|Q则退出交互模式:" var
if [ $var -eq 1 ];then
#echo 当前string变量的长度是: ${#string}
echo 当前string变量的长度是: echo ${string}|wc -L
fi
if [ $var -eq 2 ];then
echo ${string//Hadoop/}
fi
if [ $var -eq 3 ];then
echo ${string/Hadoop/Linux}
fi
if [ $var -eq 4 ];then
echo ${string//Hadoop/Linux}
fi
if [ $var == q ];then
exit
fi
if [ $var == Q ];then
exit
fi