shell的变量
什么是变量
变量即变化的量,核心是“变”与“量”二字,变即变化,量即衡量状态。
量:是记录现实世界当中的某种状态
变:指的是记录的状态是可以发生变化的
为什么使用变量
程序执行的本质就是一系列状态的变化,变是程序执行的直接体现,所以我们需要有一种机制能够反映或者说是保存下来程序执行时状态以及状态的变化。
是为了让计算机能够像人一样去将一个事物的状态记忆下来(存到计算机内)
存
,永远不是目的,目的是为了。取
让计算机以后在使用的时候,可以取出来。
例如:
1.在游戏中,英雄的等级为1,打怪升级(变)10级
2.游戏中人物名字:ljy,使用了改名卡,变为:ljynb
3.植物大战僵尸:僵尸的存活状态为True,被植物打死了,变为False
如何使用变量
例:赋值符号"=" 变量值
变量 赋值符号 变量值
name = ljy
name: ljy # yaml语法
# 编写脚本
vim 1.sh
#!/bin/bash
name=ljy # 修改变量
age=18
echo $name # 调用变量
echo $age
# 执行脚本
[root@web02 ~]# sh 1.sh
ljy
18
定义变量的语法(分三部分):
-
变量名 相当于一个门牌号,便于取出变量值,是访问到值的唯一方式
-
赋值符号 将值的内存地址,绑定给变量名
-
变量值 用来表示状态 变量的使用规则:先定义,在通过变量名去引用。
定义变量名规范
变量名的命名规则:
-
变量名的命名应该能够反映出值记录的状态。
-
变量是用来访问变量值的,所以变量名应该遵循一定规范,来方便我们标识存到内存中值的功能。
1.变量名只能是 字母、数字或下划线的任意组合(区分大小写)
例如:
x=1
X=2
是两个变量
2.变量名的第一个字符不能是数字
例如:
1x=1
123_x=1
3.尽量不要使用命令设置变量
例如:[echo,ls,cd,pwd...]
定义变量名方式
变量名定义方式
1.下划线(纯小写)
age_of_oldboy=73 #python推荐使用
2.驼峰体 AgeOfOldboy=733.不好的方式
-
变量名为中文、拼音
-
变量名过长
-
变量名词不达意
3.下划线(纯大写)
AGE_OF_OLDBOY=749
变量的分类
环境变量
系统创建的变量,在环境变量文件中
# 查看方式
env
declare
export
# 环境变量配置文件路径(优先级由上往下排)
/etc/profile
/etc/profile.d
~/.bashrc
/etc/bashrc
# 重点记住
LANG //字符集语言 LANG=zh_CN.UTF-8
PATH //该变量中的路径里面所有的可执行文件,可以直接执行,不用加路径
PS1 //命令提示符
UID //查看登录当前用户的UID
HOSTNAME //当前的主机名
PWD //当前工作所属的路径
USER //当前登录的用户
# 了解历史相关变量 (echo $*)
HISTSIZE //历史命令显示行数
HISTFILESIZE //历史命令缓存文件保存行数
HISTFILE //历史命令缓存文件保存路径
TMOUT //设置超时时间 超过设置的时间就退出
HISTCONTROL: export HISTCONTROL=ignorespace //离职专用变量 任何命令前面加空格不会被history追踪到
PROMPT_COMMAND //跳板机专用变量
普通变量
局部变量,在脚本中自定义的变量
# 普通变量没什么好强调的,但是有一点,变量分隔一定要注意
## 还记得在做rsync同步的时候,以主机名,IP,时间命名目录
DATE=$(date +%F-%T)
IP=$(ifconfig eth0|awk 'NR==2{print $2}')
mkdir $DATE_$IP_$HOSTNAME ## 基本凉了
### 注意使用大括号分隔变量
mkdir ${DATE}_${IP}_${HOSTNAME}
# 与环境变量相关的文件
/etc/profile
/etc/bashrc
~/.bashrc
~/.bashrc_profile
/etc/profile.d/*.sh
特殊变量-位置
匹配脚本参数,服务状态,特殊替换(重点)
应用场景:
1.提高书写脚本及脚本执行效率
2.判断服务状态、脚本参数、删除、替换
位置变量
符号 | 含义 | 应用 |
---|---|---|
$0 | 脚本名字 | 脚本使用方法常用:给出错误提示或者使用帮助 |
$n | 脚本的第N个参数 | 命令传参,传递给脚本,在脚本中使用 |
$# | 统计脚本参数的个数 | 判断脚本是否传参 |
$* | 获取脚本所有的参数 | 将所有参数当成是一个整体,对传递的参数进行判断 |
$@ | 获取脚本所有的参数 | 将每一个参数当成是一个整体,对传递的参数进行判断 |
使用案例 $n
[root@web02 ~]# cat test.sh
#!/bin/bash
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11}
[root@web02 ~]# sh test.sh 1 2 3 4 5 6 7 8 9 10 11
1 2 3 4 5 6 7 8 9 10 11
[root@web02 ~]# sh test.sh a b c d e f g h i j k
a b c d e f g h i j k
使用案例 $0
[root@web02 ~]# cat test.sh
#!/bin/bash
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11}
echo $0
[root@web02 ~]# sh test.sh 1 2 3 4 5 6 7 8 9 10 11
1 2 3 4 5 6 7 8 9 10 11
test.sh
使用案例 $
[root@web02 ~]# cat test.sh
#!/bin/bash
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11}
echo $0
echo $#
[root@web02 ~]# sh test.sh 1 2 3 4 5 6 7 8 9 10 11
1 2 3 4 5 6 7 8 9 10 11
test.sh
11
使用案例 $*
# 不适合数组使用,调用使用的双引 //接收脚本后面所有的参数
# 横着看
[root@web02 ~]# cat test.sh
#!/bin/bash
echo $1 $2 $3
echo $0
echo $#
echo $*
[root@web02 ~]# sh test.sh 1 2 3 4 5 6 7 8 9 10 11
1 2 3
test.sh
11
1 2 3 4 5 6 7 8 9 10 11
使用案例 $@
# 适合后面数组数据类型使用 调用使用双引 //接收脚本后面所有的参数
# 竖着看
[root@web02 ~]# cat test.sh
#!/bin/bash
echo $1 $2 $3
echo $0
echo $#
echo $@
[root@web02 ~]# sh test.sh 1 2 3 4 5 6 7 8 9 10 11
1 2 3
test.sh
11
1 2 3 4 5 6 7 8 9 10 11
查看$*与$@的区别
[root@web02 ~]# cat test1.sh
#!/bin/bash
echo '$*结果:'
for i in "$*";do
echo $i
done
echo '$@结果:'
for i in "$@";do
echo $i
done
[root@web02 ~]# sh test1.sh 1 2 3 4 5 6 7
$*结果:
1 2 3 4 5 6 7
$@结果:
1
2
3
4
5
6
7
特殊变量-状态
符号 | 含义 | 应用 |
---|---|---|
$? | 上一条命令的返回值 | 判断命令的执行是否成功 |
$$ | 当前脚本运行的pid | 在脚本运行时将pid记录到文件中,方便kill |
$! | 上一个运行脚本的pid | |
$_ | 上一个命令或者脚本的最后一个参数 | 类似于ESC + . |
$?
# 表示上一条命令的执行状态(也是上一条命令的返回结果)
# 即使执行成功,返回值也是1
false
diff
$$
# 当前脚本的pid号
[root@web01 ~]# cat test.sh
#!/bin/bash
# File Name: test.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-26 09:22
echo $1 $2 $3
if [ $# -gt 3 ];then
echo $0 '请输入三参数'
fi
echo $$
[root@web01 ~]# sh test.sh
7169
$_
[root@web01 ~]# cat 2.sh
#!/bin/bash
# File Name: 2.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-25 09:09
echo "Hello world"
ls -l /etc/passwd
echo $_
[root@web01 ~]# sh 2.sh
Hello world
-rw-r--r--. 1 root root 798 Apr 11 16:21 /etc/passwd
/etc/passwd
变量子串(复杂,但实用)
语法 | 含义 |
---|---|
${parameter} | 调用变量 |
${#parameter} | 变量的长度 |
${parameter:offset} | 截取变量,从offset之后 |
${parameter:offset:length} | 截取变量,从offset之后取指定长度 |
${parameter#word} | 从变量开头,删除最短匹配word的子串 |
${parameter##word} | 从变量开头,删除最长匹配word的子串 |
${parameter%word} | 从变量结尾,删除最短匹配的word的子串 |
${parameter%%word} | 从变量结尾,删除最长匹配的word的子串 |
${parameter/pattern/string} | 使用string替换第一个pattern |
${parameter//pattern/string} | 使用string替换所有的pattern |
${#parameter}
${#变量名}
# 变量长度
name=ljy
echo ${#name}
# 写法一 (推荐)
[root@web01 ~]# cat mima.sh
#!/bin/bash
# File Name: mima.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-26 10:21
echo "------注册账号------"
read -p "请输入账号:" name
read -p "请输入密码:" pas
echo ${#pas}
if [ ${#pas} -lt 8 ];then
echo "密码必须大于等于8位"
else
echo "密码合格"
fi
# 写法二
[root@web01 ~]# cat mima.sh
#!/bin/bash
# File Name: mima.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-26 10:21
echo "------注册账号------"
read -p "请输入账号:" name
read -p "请输入密码:" pas
len=`echo $pas | awk '{print length()}'`
if [ $len -lt 8 ];then
echo "密码必须大于等于8位"
else
echo "密码合格"
fi
[root@web01 ~]# sh mima.sh
------注册账号------
请输入账号:niubi
请输入密码:1234
4
密码必须大于等于8位
[root@web01 ~]# sh mima.sh
------注册账号------
请输入账号:niubi
请输入密码:123456789
9
密码合格
${parameter:offset}与${parameter:offset:length}
${变量:偏移量}
${变量:偏移量 :步长}
从第几个字符开始截取 截取多少个
[root@web01 ~]# sh 1.sh
eb01
[root@web01 ~]# cat 1.sh
#!/bin/bash
# File Name: 1.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-26 10:55
name=web01_yysyys
echo ${name:1:4}
[root@web01 ~]# sh 1.sh
eb01
${parameter#word}与${parameter##word}
${变量名#字符串} 从变量开头,删除最短匹配word的子串
${变量名##字符串} 从变量开头,删除最长匹配word的子串
[root@web01 ~]# cat 1.sh
#!/bin/bash
# File Name: 1.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-26 10:55
name=/tmp/abdc/1.txt
echo ${name#*/}
echo ${name##*/}
[root@web01 ~]# sh 1.sh
tmp/abdc/1.txt
1.txt
${parameter%word}与${parameter%%word}
${变量名%字符串} 从变量结尾,删除最短匹配word的子串
${变量名%%字符串} 从变量结尾,删除最长匹配word的子串
[root@web01 ~]# cat 1.sh
#!/bin/bash
# File Name: 1.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-26 10:55
name=/tmp/abdc/1.txt
echo ${name%/*}
echo ${name%%/*}
[root@web01 ~]# sh 1.sh
/tmp/abdc
${parameter/pattern/string}与${parameter//pattern/string}
${变量名/匹配内容/替换内容} 替换第一个匹配到的字符
${变量名//匹配内容/替换内容} 替换所有匹配到的字符
[root@web01 ~]# cat 1.sh
#!/bin/bash
# File Name: 1.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-26 10:55
read -p '输入用户名' name
echo ${name/xxx/yyy}
[root@web01 ~]# sh 1.sh
输入用户名xxx_xxx_xxx
yyy_xxx_xxx
[root@web01 ~]# cat 1.sh
#!/bin/bash
# File Name: 1.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-26 10:55
read -p '输入用户名' name
echo ${name//xxx/yyy}
[root@web01 ~]# sh 1.sh
输入用户名xxx_xxx_xxx
yyy_yyy_yyy
拓展变量
给变量设置默认值
写法 | 含义 |
---|---|
${parameter:-string} | 如果parameter没被赋值或其值为空,就以string作为默认值 |
${parameter:=string} | 如果parameter没被赋值或其值为空,就以string作为默认值,并将string赋值给parameter |
${parameter:?string} | 如果parameter没被赋值或其值为空,就以string作为错误输出,否则显示parameter内容 |
${parameter:+string} | 如果parameter没被赋值或其值为空,就什么都不做,否则用string替换变量内容 |
${parameter:-string}
${变量名:-字符串} 如果变量没有被赋值或者位空,那字符串就作为一个默认值
- 执行完了 字符串的值不会赋予给变量名
${parameter:=string}
${变量名:=字符串} 如果变量没有被赋值或者位空,那字符串就作为一个默认值,并赋值给变量
= 执行完了 字符串的值会赋予给变量名 如果用户没有传递(没有赋值过)就会赋值给变量名
${parameter:?string}
${变量名:?字符串} 如果变量没有被赋值或者位空,那字符串就作为一个错误输出,否则则会显示变量名
${parameter:+string}
${变量名:+字符串} 如果变量没有被赋值或者位空,那就什么都不做,否则则会赋值给变量
变量的赋值方式
- 直接赋值,简单粗暴,例:name=zls
- 间接赋值,我们将一个命令执行的结果赋值给一个变量,例:IP=
ifconfig eth0|awk 'NR==2{print $2}'
- 交互赋值,我们需要跟脚本进行交互,例:read
- 传参赋值,执行脚本的时候,将需要传递的变量值,写在脚本的后面 $1 $2 $3
交互赋值
read
-p 打印一句话
-s 不显示输入的内容(静默输出)
-t 设置超时时间,超过时间退出脚本
-a 将传递的变量使用数组接收
[root@web01 ~]# cat denglu.sh
#!/bin/bash
# File Name: denglu.sh
# Version: v1.1
# Author: ljy
# Domain: ljy_main
# Date Time: 2023-06-26 12:01
read -p 'web01 login:' -a name
read -t 5 -s -p 'Password:' pas
password=12345678
if [ $pas == $password ];then
echo '登录成功'
echo ${name[0]}
echo ${name[1]}
echo ${name[2]}
else
echo '密码错误'
fi
[root@web01 ~]# sh denglu.sh
web01 login:xxx yyy zzz
Password:登录成功
xxx
yyy
zzz
[root@web01 ~]# sh denglu.sh
web01 login:xxx yyy eee
Password:密码错误
Shell 数据类型
- 字符串
# 字符串赋值
name=ljy
# 取值
echo $name
ljy
- 整型
# 整型赋值
age=18
# 取值
echo $age
18
- 数组
# 数组赋值
list=(python java golong shell)
list[0]='abc'
list[1]='bcd'
list[2]='scb'
# 取值
echo ${list[0]}
python
echo ${list[1]}
java
echo ${list[2]}
golong
echo ${list[3]}
shell
echo ${list[-1]}
shell
lt 小于
gt 大于
eq 等于
le 小于等于
ge 大于等于
ne 不等于
#!/bin/bash
read -p 'Input New Hostname' h
read -p 'Input Net IP' IP
hostnamectl set-hostname $h
sed -i "s#100#$IP#g" /etc/sysconfig/network-scripts/ifcfg-eth{0,1}
systemctl restart network
作业
安装服务的脚本
-i 安装
-d 卸载
如果输入了除了 -i -d 意外的内容 提示脚本名字 用法 推出脚本 exit
安装 提示安装成功与否 成功return 6 失败 return 7
卸载 提示卸载成功与否 成功return 8 失败 return 9
变量字串修改网卡信息
sed 命令中用变量字串
IP可以用截取
外网和内网 主机位不一致
sed 命令一条全部替换外网和内网
网卡替换脚本
#!/bin/bash
read -p 'Input New Hostname:' h
read -p 'Input New IP:' IP
hostnamectl set-hostname $h
eth0=`(ifconfig eth0| awk 'NR==2{print $2}')`
eth1=`(ifconfig eth1| awk 'NR==2{print $2}')`
sed -i /IPADDR/"s#\b${eth0##*.}\|${eth1##*.}\b#$IP#g" /etc/sysconfig/network-scripts/ifcfg-eth{0,1}
systemctl restart network
安装服务脚本
#!/bin/bash
function install(){
if [ $1 == '-i' ];then
yum install -y $2 &>/dev/null
num=`rpm -qa | grep -c $2`
if [ $num -gt 0 ];then
echo '安装成功'
return 6
else
echo '安装失败'
return 7
fi
elif [ $1 == '-d' ];then
yum remove -y $2 &>/dev/null
num=`rpm -qa | grep -c $2`
if [ $num -eq 0 ];then
echo '卸载成功'
return 8
else
echo '卸载失败'
return 9
fi
else
echo '大哥用错啦!'
echo '正确安装用法:Install -i tree'
echo '正确卸载用法:Install -d tree'
exit
fi
}
install $1 $2