变量和运算符
bash 中的变量和运算符
变量即可以变化的量 —— 存放数据的容器
- 常量 —— 不会变化的数值
变量的定义准则 —— 变量的命名规范
- 变量名称可以由字母、数字和下划线组成
- 不能以数字开头,变量中间不能有空格 —— “2name”,错误示范
注:变量的值如果有空格,需要使用单引号或双引号包括 —— 如 test=“hello world”
变量的分类
- 自定义变量 —— 自己创建的变量,注意命名规范
- 数值变量 —— 需要单独声明类型,用于保存数值型数据,默认保存的数值是字符型
- 数组变量 —— 保存多个同类型的数据
- 环境变量 —— 根据登录环境的不同使用不同的值
- 预定义变量 —— $?
- 位置参数变量
变量的声明方式
- 变量名=值
- read -p “提示词” 变量名
- echo -n “提示词” ; read 变量名
变量的调用
- echo ${变量名} —— 大括号可以表示括号内的字符是一个整体
数值运算器:
- echo $((运算式))
- echo $[运算式]
注:小括号和中括号的数值运算器作用相同,但都只能进行整数运算
例1:在 Bash 中变量的默认类型都是字符串型,若要进行数值运算必须修改变量类型为数值型
x=666 ; y=888 ; s=$x+$y ; echo $s #输出结果:666+888
x=666 ; y=888 ; s=$(($x+$y)) ; echo $s #对比结果:1554
例2:编写一个简单功能的计算器
#需求分析
# 1. 基本的加减乘除能实现
# 2. 两个数值间的运算
# 3. 可以自定义数值和运算符号
#!/bin/bash
echo -n "请输入要计算的第一个数值:"
read x
echo -n "请输入要计算的运算符(+ - * /)"
read y
echo -n "请输入要计算的第二个数值:"
read z
echo $(($x$y$x))
例3:对例2 编写的计算器脚本进行进一步升级
#!/bin/bash
echo -n "请输入要计算的运算式:"
reax x
echo $(($x))
写脚本的思路:
- 需求分析 & 素材整理
- 手动执行该任务所需的所有素材:命令、目录、文件、权限、、、
- 执行步骤
- 构建脚本
- 先构建骨架 —— 大致的功能
- 功能测试
- 然后再给每一个步骤添加单独的功能
例1:编写一个脚本,自动配置本地 yum 源
#!/bin/bash
#mount /dev/sr0 /media/
[ -b /dev/sr0 ] && mount /dev/sr0 /media/ || echo "sr0不存在"
cd /etc/yum.repos.d/
mkdir bak
mv C* bak
echo "[CentOS]
name=xxx
baseusrl=file:///media/
enable=yes
gpgcheck=0" >> CentOS-Media.repo
说明:先写出大致框架,然后再对脚本进行完善 —— 加入了对本地介质,sr0 的判断
例2:生成随机字符,然后使用 tr 和 cut 进行过滤截取
read -p "请输入要生成密码的长度:" len # 接受键盘输入
read -p "请输入要生成密码的个数:" num # 并定义变量取值
pass=$(head -5 /dev/urandom | tr -dc a-zA-Z0-9\@\_\(\-\* | cut -c 1-$len)
echo $pass
注:read 命令可以接受用户的键盘输入,-p 是输出提示语句,tr -dc 是过滤字符,cut -c 是截取字符范围
数值变量
普通变量默认都是字符串
x=100 ; y=200 ; sum=$x+$y #结果是 100+200,"+" 表示字符串的连接
例1:将 sum 声明成数值型,即可运算
x=100 ; y=200
declare -i sum=$x+$y #结果是 300,使用 declare 可声明任意类型的变量
例2:运算式格式,对变量进行运算
x=100 ; y=200
sum=$(($x+$y)) ; echo sum #结果是 300,使用 $(()) 的方式进行变量运算
declare —— 声明变量的命令
- declare -p 变量 —— 查看变量类型
- declare -x 变量 —— 声明环境变量,作用同 export
- 环境变量会根据用户身份的不同而修改变量的值
- declare -i 变量 —— 声明数值变量
- declare -r 变量 —— 声明只读变量,r = ro
- 只读变量只能进行调用,不能进行修改和删除,也不能取消只读选项
例:只读变量
declare -r test=100w ; echo $test # 输出 100w,可以调用
test=200w # 只读变量,不可修改
unset test # 只读变量,不可取消
declare +r test # 取消变量的只读选项
注:变量退出终端,即会消失,这样设置的变量都是临时性的
补:env —— 查看所有环境变量,set —— 查看所有变量,unset —— 取消一个变量
使用 expr 或 let 进行运算 —— 其它运算工具
- 直接声明运算过程是数值运算,而不是通过声明变量的类型 —— 相对简单
例1:expr —— 注意格式
x=100 ; y=200
expr $x + $y #直接输出 300,一定要注意 "+" 两端要有空格,否则是字符串连接
注:expr 使用时需要注意的是,在运算符两边要有空格,否则不会正常运算
例2:let 相对简单易用,原理相同 —— 注意格式变化
x=1000 ; y=2000
let z=$x+$y ; echo $z # 输出运算后的结果 3000
注:let 还能进行自增自减,或者指定增加量或减少量
例3:使用 let 进行自增、自减运算
n=1 ; echo $n # 需要对 n 进行自增
let n++ ; echo $n # 使用 let n++ 让 n 自增 1
let n+=1 ; echo $n # 使用 "+="、"-=" 方式自增
说明:+=、-=、*=、/= —— 表示 n = n + 、n = n -、、、
常用运算符
shell 常用运算符
优先级 | 运算符 | 功能描述 |
---|---|---|
1 | +、- | 正、负 |
2 | *、/、% | 乘、除、取余 |
3 | +、- | 加、减 |
4 | +=、-=、、、 | 自增、自减、、、 |
运算符是有优先级别的
例:取余运算
echo $((14%3)) # 2
echo $((-14%3)) # -2
echo $((14%-3)) # 2
echo $((-14%-3)) # -2
注:取余运算的符号,取决于被除数,前面的那个数
补:RANDOM —— 生成随机数的环境变量,配合取余运算
echo $(($RANDOM%100)) # 取 0-99 的随机数
echo $(($RANDOM%100+1)) # 取 1-100 的随机数
注:对 100 取余,可以代表是要取 100 的数,小于 100 的数,所以是 0-99
扩展 —— 取模运算
- 其他语言中除了取余之外,还有取模运算
- 求整数商:c = a / b
- 计算模或者余数:r = a - c * b
注意:当 a 和 b 符号一致时,求模运算和求余运算所得的 c 的值一致,因此结果一致
- 但是当符号不一致的时候,结果不一样,具体来说
- 求模运算结果的符号和 b 一致,求余运算结果的符号和 a 一致
注:shell 并不支持取模运算,所以了解即可
逻辑与
echo $((0&&0)) # 0
echo $((0&&1)) # 0
echo $((1&&0)) # 0
echo $((1&&1)) # 1
逻辑运算,逻辑与有零则零,全一为一,逻辑或有一则一,全零为零
变量叠加
变量叠加
- PATH —— 命令所在路径的环境变量
- echo $PATH —— 输出环境变量
- PATH=$PATH:/bash —— 在原有基础上叠加一个 /bash 目录
例:不同用户的 PATH 环境变量的值是不同的
# root 用户
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
# 普通用户
[nc1239@localhost ~]$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/nc1239/.local/bin:/home/nc1239/bin
说明:
- 若是用户的家目录中有 /bin 目录,则在命令查找路径范围之中
- 超级用户可以执行任何命令,所以超级用户的命令搜索路径排序可以任意
- 普通用户没有权限执行 /usr/local/sbin 中的命令,所以普通用户 /usr/local/bin 目录要排在前面
问:为什么不同的用户同一个变量,含有不同的结果?—— 环境变量的特点
- 环境变量:根据登录环境的不同使用不同的值
将自己编写的脚本变成可执行的命令 —— 两种方式
- 将脚本放在命令的搜索路径,让系统可以找到 —— 将脚本放在 PATH 环境变量的范围
- 让 PATH 环境变量包含,我们自己创建的脚本目录 —— 扩展 PATH 环境变量的范围,变量叠加的体现
对 PATH 环境变量做变量结果的叠加 —— 不破坏原有的值,在原有基础上追加新值
- PATH=$PATH:/bash —— 原值不变,增加了一个新值
如此:根目录下的 “/bash” 目录中的脚本都可以以执行命令一样方式执行
例:各个用户家目录的 “.bashrc” 文件
# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
PATH='$HOME/.local/bin:$HOME/bin:$PATH' # 变量叠加
fi
export PATH
说明:不管什么用户,都是在原有的四个基础目录,叠加的用户家目录下的目录 —— 系统提供的叠加方案
注:CentOS 7 变量叠加是在 ~/.bash_profile 文件中定义的
环境变量
补充:umask —— 权限掩码
# 该段代码的作用是判断用户创建文件时使用的掩码值
if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`"]
then
umask 002 # 如果用户 UID 大于 199,并且用户名和组名相同,使用 002 掩码
UMASK=002 # 在原有基础上,创建一个变量 UMASK=002
else
umask 022 # 否则 umask 值默认 022
UMASK=022 # 在原有的基础上,创建一个变量 UMASK=022
fi
说明:定义了环境变量 UMASK,可以通过 echo $UMASK 的方式得到环境变量的值
环境变量
- 同一个系统内,根据登录用户身份的不同,为同一个变量设置不同值的方式,就叫环境变量
补充:PS1 —— 不是环境变量
- echo $PS1 --》[\u@\h \W]\$ —— 命令提示符的格式
- [root@localhost ~]# —— [用户名@hostname where]用户身份类型
- [nc1239@localhost ~]$ —— 普通用户是 “$”,root 用户是 “#”
注:虽然是不同用户有不同的值,但 PS1 不是环境变量
创建环境变量的条件:
- 根据登录环境的不同使用不同的值
- 使用特定的命令声明变量的类型
声明环境变量:
- export PATH=$PATH:/bash —— 这样声明的才叫环境变量
- PATH=$PATH:/bash --》export PATH —— 两种方式
相关命令
查看变量的命令:
- set —— 列出当前解析器中所有已加载的变量和函数(所有类型的变量)
- env —— 仅列出当前解析器中所有已加载的环境变量
例1:使用 set 命令列出所有变量,统计个数
set | more #分页显示
set | wc -l #统计个数
例2:使用 env 命令列出所有变量,统计个数
env | wc -l #统计环境变量个数
env | grep "PA1" #PA1 不是环境变量,所以找不到
env | grep "PATH"
env | grep "LANG" #language,语言
删除\取消变量:
- unset —— 删除或取消变量(所有类型的变量都可以取消)
例:定义变量,再使用 unset 取消变量
num1=100; echo $num1; set | grep num1
unset num1; set | grep num1; echo $num1
说明:“_” 用于保存上次被调用过的变量名称
判断变量类型:
- declare -p PATH —— 查看变量类型
说明:
- -x —— 环境变量
- – —— 普通变量,字符
问:整数类型变量的变量类型用什么表示?—— -i
声明变量 —— 不同类型
- declare —— 声明变量,指定类型
- -x —— 声明环境变量,和 export 是同样的效果
- -i —— 声明整数型变量
例:声明整数型变量
declare -i num1=100
declare num2=200
declare -p num1 # declare -i num1="100"
declare -p num2 # declare -- num2="200"
位置参数变量
例1:编写一个脚本
[root@localhost ~]# cat 3.sh
#!/bin/bash
echo "$1" # $1 是一个整体,类似 $?
[root@localhost ~]# ./3.sh nc1239
nc1239 # 直接输出
注:$1 的作用是调用脚本外的第一个值
例2:改变一下
[root@localhost ~]# cat 3.sh
#!/bin/bash
echo "$(($1))" # 如此,可以进行运算式的运算
[root@localhost ~]# ./3.sh 1+2+3+4
10 # 输出计算结果
例3:对比,和之前的运算器脚本
[root@localhost ~]# cat 1.sh 2.sh 3.sh
#!/bin/bash
echo -n "请输入要计算的第一个数值:"
read x
echo -n "请输入要计算的运算符(+ - * /)"
read y
echo -n "请输入要计算的第二个数值:"
read z
echo $(($x$y$z)) # 1.sh
#!/bin/bash
echo "请输入运算式:"
read x;echo $(($x)) # 2.sh
#!/bin/bash
echo $1 # $1 变量
例4:位置参数变量 —— 位置参数变量的格式
-
vim 4.sh
#!/bin/bash echo $1 echo $3 echo $5 echo $10 echo ${10}
-
测试1
[root@localhost ~]# ./4.sh 1 2 3 4 5 6 7 8 9 10 1 3 5 10 # 问题位置 10
-
测试2
[root@localhost ~]# ./4.sh a b c d e f g h i j k a c e a0 # 发现问题 j
-
实际上,$10 调用的是第一个值,然后加上了一个 0,两位的数字必须加上大括号 {}
位置参数变量
- 按参数排列位置,调用参数,所以叫做位置参数变量
- $n —— 代表脚本后的第几个值
- $0 —— 代表脚本本身,代表调用的是脚本的名字,第 0 个,也就是调用脚本的字符串
- $@ —— 将所有参数逐个,依次调用
- $* —— 将所有参数当作一个整体调用
- $# —— 统计输入的参数个数
例1:对比不同位置参数变量的区别
-
对比:
#!/bin/bash echo "$1" echo "$3" echo "$5" echo "$0" echo "$@" echo "$*"
-
测试:
[root@localhost ~]# ./4.sh a b c d e f a c e ./4.sh # $0 a b c d e f # $@ a b c d e f # $*
注:位置参数变量的 $0 表示的是调用过程中的第 “1” 个,即脚本自己本身的名字
例2:循环结构,使用 $@ 对输入的参数逐个调用
-
vim 5.sh --》chmod +x 5.sh
#!/bin/bash echo "您一共输入了 $# 个值" # $# 统计的参数个数就是循环次数 n=1 for i in "$@" #将每一个值取出,赋值给 i do echo "第 $n 个位置的值是:$i" #将 i 的值依次输出 let n=n+1 # n 用于计数 done
-
测试
[root@localhost ~]# ./5.sh 1 2 3 4 5 您一共输入了 5 个值 第 1 个位置的值是:1 第 2 个位置的值是:2 第 3 个位置的值是:3 第 4 个位置的值是:4 第 5 个位置的值是:5
例3:使用 $* 将所有参数当作一个整体输出 —— 只当作了一个字符串
-
修改其中一行:
for i in "$*"
-
对比 $@
[root@localhost ~]# ./5.sh 1 2 3 4 5 您一共输入了 5 个值 第 1 个位置的值是:1 2 3 4 5
注:$@ 和 ∗ 都是将脚本后的所有值,保存并输出,但过程不同, * 都是将脚本后的所有值,保存并输出,但过程不同, ∗都是将脚本后的所有值,保存并输出,但过程不同,* 是将所有参数当做整体,$@ 是一个一个传递,独立单独的个体
总结 —— 位置参数变量
- $n —— 代表脚本后的第一几个值
- $0 —— 代表脚本本身
- $@ —— 依次保存传递值
- $* —— 将所有值保存为一个整体,即一个值
- $# —— 统计脚本后值的数量
预定义变量
预定义变量
- $? —— 最后一次执行的命令返回状态
- 如果这个变量的值为 0,证明上一个命令正确执行
- 如果这个边的值为非 0,则证明上一个命令执行不正确(具体是什么数字由命令本身决定)
- $$ —— 当前进程的进程号,PID
- $! —— 后台运行的最后一个进程的进程号,PID
例1:编写自动配置本地 yum 源的脚本 —— 判断语句,自定义错误提示以及 $? 收集错误提示
-
vim a.sh --》chmod +x a.sh
#!/bin/bash [ ! -b /dev/sr1 ] && exit 23 # 若sr1不存在,则退出,提示 23 # 注:-b可判断块设备文件是否存在,!将结果取反,所以是不存在则为真,sr1不存在,就提示错误信息 23
-
测试:echo $?
[root@localhost ~]# ./a.sh [root@localhost ~]# echo $? 23
综上:echo $? —— 这条语句,给出的报错数字是可以自己定义的
例2:编写自动配置本地 yum 源的脚本 —— 完善
#!/bin/bash
# 第一行声明命令解析器是 /bin/bash
[ -b /dev/sr0 ] && mount /dev/sr0 /media/ || exit 12
# 判断块设备 /dev/sr0 是否存在,存在则挂载,否则提示错误数字 12
cd /etc/yum.repos.d/ #切换到 yum 配置文件目录
[ -d bak ] && echo "目录已存在" || mkdir bak
# 判断目录 bak 是否存在,存在则提示,否则创建 bak,用于保存 yum 配置文件
mv C* bak #剪切所有 C 开头的文件到 bak 目录
echo "[c7-media] #使用追加内容的方式,非交互的配置yum
name=CentOS-$releasever - Media
baseurl=file:///mnt
gpgcheck=1
enabled=1 #追加的方式可以创建文件,新建配置文件
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7" >> CentOS-Media.repo
总结 —— 位置参数变量
- $? —— 最后一次执行的命令返回状态
- $$ —— 当前进程的进程号,PID
- $! —— 后台运行的最后一个进程的进程号,PID