shell变量

发布于:2025-06-07 ⋅ 阅读:(14) ⋅ 点赞:(0)

文章目录

1.什么是变量

shell中的变量都是字符串类型,不同于其他语言的不同数据类型所对应的不同格式。

1.1、变量的赋值和修改

赋值:name = “zhangsan”
修改:name = $(hostname)

在这里插入图片描述
堆积的shell脚本重复执行一般都会报错(执行过程中会发生端口冲突等问题),所以这个时候我们就需要动态的去获取变量的值并进行对应的判断。所以基于此,变量的作用就显示出来了—动态的表示数据的变化
所以我们通常是通过配置文件来对程序进行动态的管理的(eg:nginx.conf中定义一个配置参数pid /var/run/nginx.pid,则获取的时候nginx_id = $(cat /var/run/nginx.pid))
在这里插入图片描述

2.变量分类

在这里插入图片描述

2.0、父子bash的关系

什么是父子bash
每次执行一次bash都会开启一个新的子bash环境。在这里插入图片描述

总结

  1. 执行一次bash,就单独开辟一个子bash环境
  2. 执行一次exsit就退出一个bash环境
  3. linux中提供了多种运行脚本的方式,区别在于,父子shell的创建【bash是新开一个子bash,并在其bash下执行命令。而source和.则是直接在父bash下执行命令】

2.1 export命令(全局变量、局部变量)

临时变量,是否添加export的区别

总结是
定义变量,是否添加export的区别(有就是全局变量)

1. 不加export,只对当前shell生效,子shell看不到;
name="不加export,儿子bash看不到这个变量,属于shell变量的细节坑"

加export,当前shell会话进程,父子shell都可以用;
[root@m-61 ~]#export name="休息一会,待会继续,先消化父子bash的作用于关系,和变量的关系"

进入子bash
[root@m-61 ~]#
[root@m-61 ~]#echo ${name}
休息一会,待会继续,先消化父子bash的作用于关系,和变量的关系

在这里插入图片描述
在这里插入图片描述

pstree -p 命令运行失败,需要安装对应的包。sudo apt-get install psmisc

2.2 加载环境变量文件的顺序

注意几点:①类似于windows,我们可以直接将PATH变量的值,直接写入到/etc/profile中去,这样实现开机就可以访问。

在这里插入图片描述

2.4 变量命名规范

命令不要使用关键字等
在这里插入图片描述

3.变量实际使用

3.1 字符串类型

shell的变量的值,都会被当做字符串去处理,但是你在写的时候,可以用不同的写法(底层都是作为字符串去处理了;写法可以不同,纯字符串的值形式)
关于定义字符串的细节

  • 单引号,所见即所得
  • 双引号,识别特殊符号
  • 反引号,用于执行linux命令时,用这个写法
  • 不加引号(不建议这么用,用于写连续的字符串时,才可以这么写)
    在这里插入图片描述

3.2 存储linux命令的执行结果 【$() 】

用变量存储linux命令的执行结果
主要学习,用什么语法可以让命令执行,且获取值。
建议获取命令执行结果,用$() ,因为太多的引号,眼花

在这里插入图片描述

3.3 提取变量值语法: ${变量名}

需要注意如下写法的区别,以及坑。
总结,建议用完整的写法,绝对不会出错
${变量名},省事写法,但是可能出错 $变量名 (丢失了字符串的边界,导致bash识别错误)

写法1,完整写法,包括简写

[root@m-61 ~]#name="吴彦祖"
[root@m-61 ~]#echo "我叫:${name}"
我叫:吴彦祖
[root@m-61 ~]#
[root@m-61 ~]#echo "我叫:$name"
我叫:吴彦祖


写法2,如果有坑的话,如下
[root@m-61 ~]#name2="超哥"
[root@m-61 ~]#echo "$name2 6666"
超哥 6666
[root@m-61 ~]#
[root@m-61 ~]#echo "$name26666"

[root@m-61 ~]#
[root@m-61 ~]## 丢失了字符串的边界,导致bash识别错误
[root@m-61 ~]## 丢失了字符串的边界,导致bash识别错误 ,建议完整写法,加上边界
[root@m-61 ~]#echo "${name2}6666"
超哥6666

3.4 修改、删除变量

在这里插入图片描述

set 和 unset 用于设置和删除Shell变量及选项
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.5、显示的是数字类型值的变量(字符串)


[root@m-61 ~]#age=18
[root@m-61 ~]#phone_num=1521000000

[root@m-61 ~]#age="18"
[root@m-61 ~]#phone_num="15200000"

[root@m-61 ~]## 在shell中,都是当做字符串去处理的,其他编程语言有明确的数据类型区别

4.变量传递,参数传递(重要)

shell内置的固定的语法规则,在脚本传递参数的过程中,直接 使用${index}去获取对应位置参数

在下面这个例子中,我们将yuchao1、yuchao2、yuchao3、yuchao4、yuchao5依次传递给vars.sh。其用脚本内部的${index}进行接受。
在这里插入图片描述

对应实际例子(系统内置的脚本用到了位置参数)
在这里插入图片描述

具体的用法
在这里插入图片描述

特殊变量的 $? 提取上一次命令执行结果
在这里插入图片描述

4.1 实战开发

1、- 通过位置参数形式- 免交互的创建linux用户与密码。

# 1. 接收位置参数的数据
# bash user_pwd.sh  yuyu01   yuyu666
username="${1}"
pwd="${2}"


# 2. 数据已经被写入变量, 可以调用变量,创建对应用户信息了
#useradd ${1}
useradd "${username}"
# 这俩一个意思,看懂刷111,都是调用useradd命令,创建用户名

# 创建密码
# echo "${pwd}" | passwd --stdin "${username}"
echo "${username}:${pwd}" | chpasswd  # ubuntu适用
echo "$?"

在这里插入图片描述
2.编写通过位置参数,自动修改主机名的脚本

# 接收新的主机名
new_hostname=$1


# 设置修改主机名
hostnamectl set-hostname ${new_hostname}

# 查看新的主机名
# 写在 $() 里面的,就是linux的命令了,而不是普通的字符串。
echo "当前新的主机名是 :$(hostname)"

5. 交互式参数传递(read命令)

利用read命令,接收用户输入,从键盘读取标准输入。
语法:read -p “提示信息” 变量名
在这里插入图片描述

5.1 用户信息接收 (read -s -p )

需求是
1. 程序和用户进行交互,需要用户输入,账户,密码2个数据
2. 程序简单的打印用数据,练习read的用法

[root@m-61 ~/part3-shell]#cat user_info_input.sh 
#!/bin/bash

# 接收账号数据
read -p "请输入你的账户:"  user


# 接收密码数据,密码,建议隐藏显示,更安全
# -s 将密码和终端颜色保持一致,导致你看不到。
# pwd这么用,对 扣 1不对 扣2
#pwd 属于覆盖系统内置命令,必然不合适。变量命名不规范了!!!

read -s -p "please input your password:"   my_pwd


# 打印输入的结果
echo "您的账户是:$user"
echo "您的密码是:$my_pwd"


# 执行测试
[root@m-61 ~/part3-shell]#bash user_info_input.sh 
请输入你的账户:yuyu01
请输入您的密码:
您的账户是:yuyu01
您的密码是:yuyu66

在这里插入图片描述
在这里插入图片描述

5.2 备份目录小脚本

# 1. 让用户输入要备份的目录 路径
# 2. 程序自动创建备份目录,且复制数据,实现备份

[root@m-61 ~/part3-shell]#cat read-backup.sh 
#!/bin/bash

# 1. 让用户输入要备份的目录 路径
read -p "请输入要备份的目录绝对路径:" src_dir
# 2. 程序自动创建备份目录,且复制数据,实现备份
read -p "请输入要备份的目的地绝对路径:"  dest_dir

# 3.创建备份目录,且把数据拷贝过来,实现备份
# 问,这个命令二次执行会报错吗? 会扣1 不会扣2
# 以咱们目前这个写法
# 解答一波,你要看你自己怎么写。 因为加上 -p参数,因此反复执行,不会导致目录创建报错
# 在学了 if 条件之后,要在这里判断
# 正确的逻辑应该是,如果目录不存在,则创建
# 存在, 则跳过mkdir的动作
mkdir -p ${dest_dir}  &&  cp -a ${src_dir}  ${dest_dir}
# 4. 脚本查看备份的数据目录信息
echo -e "备份的数据如下:\n$(ls ${dest_dir})"


[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#bash read-backup.sh 
请输入要备份的目录绝对路径:/var/log
请输入要备份的目的地绝对路径:/tmp/log/
备份的数据如下:
log

mkdir -p ${dest_dir} && cp -a ${src_dir} ${dest_dir} 命令解释:

  • 使用了&&操作符连接,只有在前一个命令成功执行后,才会执行后续的命令。
  • mkdir -p ${dest_dir} 中 -p 选项确保在创建目标目录时,如果其父目录不存在,则会自动创建这些父目录。

第二部分 cp -a ${src_dir} ${dest_dir}

  • cp 命令用于复制文件和目录
  • -a 选项表示归档模式

5.4 用户输入综合小练习(实践)

需求
接收用户输入 read 的数据,创建系统用户;(账户,密码)
且将用户输入保存到文件/tmp/user_info.log,保存格式为username:pwd 键值对形式

风格1,交互式让用户输入数据

# 接收账户
read -p "please input your account:"  your_user
# 接收密码
read -p "please input your password:"  your_password

# 用数据, 创建系统用户且设置密码
useradd ${your_user}
echo "${your_password}" | passwd --stdin ${your_user} > /dev/null 2>&1

# 打印数据,写入到文件里
echo "${your_user}:${your_password}" >> /tmp/user_info.log

2>&1 :将标准错误输出(文件描述符2)重定向到标准输出(文件描述符1)的位置,任何错误信息也会被重定向到/dev/null,从而不会显示在终端上,也不会被保存到文件中在这里插入图片描述

5.5 修改主机IP、主机名脚本(实践)

代码解释:sed -i “/IPADDR=/c IPADDR=${new_ip}” /etc/sysconfig/network-scripts/ifcfg-eth0
在这里插入图片描述

#!/bin/bash
# 代码是自上而下加载的。

read -p "请输入新的主机名:"  new_hostname
# 立即修改
hostnamectl set-hostname ${new_hostname}


# 替换ip
read -p "请输入新的ip地址:"  new_ip
sed -i "/IPADDR=/c IPADDR=${new_ip}" /etc/sysconfig/network-scripts/ifcfg-eth0

# 显示替换结果
echo -e "当前主机名是:\n$(hostname)"
echo -e "当前的网卡配置文件是:\n$(cat /etc/sysconfig/network-scripts/ifcfg-eth0 )"

# 重启network服务
echo "重启网络服务中。。。。"
systemctl restart network


# 统一的修改
# 修改配置文件,重启network服务
# 方案1,直接用 sed的c命令,整行替换数据
# 方案2,用sed的s命令,替换整个ip
# 方案3,用sed的s命令,只替换ip最后一个的主机位地址。
# 这3个方案,听懂 刷3333
# 方案有很多,随着你代码写的多了,写熟练了,心中自然也就有了很多的解决方案了。

5.6 定时任务脚本

/var/spool/cron/root文件中该文件包含了root用户crontab任务列表,使用crontab -l列出当前用户的所有定时任务。
在这里插入图片描述
ntpdate 命令在这里插入图片描述

# 方案1:写法简单粗暴的,直接输入完整的语句
read -p "请输入您要插入的新定时任务完整规则:"  new_crontab

echo "${new_crontab}" >> /var/spool/cron/root # 直接写入用户文件中

echo "当前的计划任务规则列表是:"
echo "$(crontab -l)"

# 每十分钟和阿里云时间服务器同步。  */10 * * * * /usr/sbin/ntpdate -u ntp.aliyun.com
使用crontab -e命令进行编辑(用户)在这里插入图片描述

实际例子:每日凌晨2点执行数据库备份脚本
在这里插入图片描述

方案2,规则和命令分开写
#!/bin/bash
read -p "请输入crontab的时间频率:" cron_time  # */5 * * * *
read -p "请输入crontab的具体命令:" cron_job   # ntp同步命令(eg:/usr/sbin/ntpdate  -u ntp.aliyun.com)

# 让用户输入生效
echo "#crontab by yuchao at $(date +%F)" >> /var/spool/cron/root
echo "$cron_time $cron_job" >> /var/spool/cron/root

echo -e "当前最新的计划任务是:\n$(crontab -l)" # */10 * * * * /usr/sbin/ntpdate  -u ntp.aliyun.com

6.预定义变量(脚本的位置参数,位置变量)

6.0、位置参数,以空格分割每一个元素,作为参数

read命令,是你所有的输入,被当做了一个大字符串传入给了 变量。
位置变量的玩法,不一样**(以空格隔开**)

  • bash vars.sh cc01 bob01 yu01 jack 01
    阿斯顿

6.1 测试预定义变量

几个特殊的位置参数变量

  • $* 接收所有位置参数
  • $@ 接收所有位置参数
  • $# 参数个数
  • $$ 获取当前进程的PID
  • $? 上一个命令的返回值,0是正确,其他都错误(指的是你脚本上,查看该命令的上一条命令)

6.2 探测主机是否存活脚本(练习$?的玩法)

$? 用于判断上一次的命令执行结果。非0就是上一条命令执行有问题

  • 交互式,read命令完成
  • 非交互式,位置变量完成

分析需求
判断主机是否存活,常见做法是,发送icmp的数据包,也就是执行ping命令
尝试用命令去完成需求

  1. ping
  2. 2.查看 echo $?
#!/bin/bash

# 传入位置参数的玩法
ping -c 1 ${1} &>/dev/null  2>&1 
# c:count 次数;&>/dev/null  2>&1 处理了标准错误和标准输出,隐藏所有由ping命令产生的输出信息,无论是正常的还是错误的信息。

if  [ "$?" == "0" ];then
	echo "该机器 ${1} 正在运行中!!!"
else
	echo "该机器 ${1} 挂掉了!!!!"
fi

6.3 获取所有位置参数(难点,是练习$@ $*的玩法)

当我们想从脚本运行,传入的参数中获取具体的参数,可以用 ${n}
但是如果用户传入的参数不固定,你知道到底用 数字写多少合适 ? 因此这时候, ‘ {数字写多少合适?} 因此这时候,` 数字写多少合适?因此这时候,@ $*的威力就来了,可以获取所有的位置参数(除了$0`)
但是这俩变量虽说 都是提取所有参数,但是提取之后的数据构造不一样

重点(记住如下用法即可)
  1. $@ $*都用于接收不定长的用户参数
  2. 脚本中使用这俩特殊变量,必须加上双引号!!!才能发挥其作用!
  3. 一般都是结合for循环去,找出这俩特殊变量存储的所有元素.

测试脚本:

echo "----------------测试\$*,给变量添加了引号用法--------------"
for v in "$*"
do
echo "传入的位置参数,分别是${v}"
done

echo "----------------测试\$@,添加了引号用法--------------"
for v in "$@"
do
echo "传入的位置参数,分别是${v}"
done

在这里插入图片描述
即为:$@的特殊之处–在直接echo变量的值的时,也是将多个参数构造成一个整体;但是如果在for循环中的话,则是能够区分出每一个元素

变量复习

在这里插入图片描述

变量练习题–采集服务器数据

  1. 采集主机信息,题意
    写脚本,提取当前机器的静态属性,包括如下,写入文件/tmp/server_info.log
============【系统版本】===============
[root@m-61 ~]#echo "当前主机,系统版本信息是:$(cat /etc/redhat-release)"
当前主机,系统版本信息是:CentOS Linux release 7.5.1804 (Core) 

# Ubuntu对应的命令
root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# cat /etc/os-release 
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# echo "当前系统版本是:$(grep -i 'pretty_name' /etc/os-release |awk -F '"' '{print $2}')"
当前系统版本是:Ubuntu 22.04.4 LTS

=======内核版本==================
[root@m-61 ~]#echo "当前系统内核版本是:$(uname -r)"
当前系统内核版本是:3.10.0-862.el7.x86_64

=======主机名==================
[root@m-61 ~]#echo "当前系统主机名是:$(hostname)"
当前系统主机名是:m-61

=======网卡配置文件==================
root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.3  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:03  txqueuelen 0  (Ethernet)
        RX packets 56747  bytes 32530359 (32.5 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 56697  bytes 8771394 (8.7 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 91685  bytes 25088113 (25.0 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 91685  bytes 25088113 (25.0 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.3  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:03  txqueuelen 0  (Ethernet)
        RX packets 56845  bytes 32545110 (32.5 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 56806  bytes 8785564 (8.7 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# ifconfig eth0 | awk 'NR==2'
        inet 172.17.0.3  netmask 255.255.0.0  broadcast 172.17.255.255
root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# ifconfig eth0 | awk 'NR==2{print$2}'
172.17.0.3

=======公网IP==================
[root@m-61 ~]#echo "当前网络环境,对外的公网IP是:$(curl -s ifconfig.me )" # 静默获取公网IP地址信息
当前网络环境,对外的公网IP是:115.171.167.199

=======内存使用率==================
root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# free -m
               total        used        free      shared  buff/cache   available
Mem:          773401       39648       40004         606      693747      728216
Swap:              0           0           0
root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# echo "当前内存已使用的百分比情况是 :$(free -m | awk 'NR==2{print $3/$2*100}')%"
当前内存已使用的百分比情况是 :5.13084%

=======磁盘使用率==================
磁盘使用率(判断,当根目录分区容量不足30%的时候,告诉运维,该扩容了)
root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# df -h
Filesystem      Size  Used Avail Use% Mounted on
overlay          30G  612M   30G   2% /
/dev/nvme1n1    7.0T  4.0T  3.1T  58% /autodl-pub
AutoFS:fs1      4.0T  1.4T  2.6T  35% /autodl-pub/data
tmpfs            64M     0   64M   0% /dev
shm             2.0G     0  2.0G   0% /dev/shm
/dev/sda2       440G   17G  401G   4% /usr/bin/nvidia-smi
tmpfs           378G   12K  378G   1% /proc/driver/nvidia
tmpfs           378G     0  378G   0% /etc/nvidia/nvidia-application-profiles-rc.d
tmpfs           378G     0  378G   0% /proc/asound
tmpfs           378G     0  378G   0% /proc/acpi
tmpfs           378G     0  378G   0% /proc/scsi
tmpfs           378G     0  378G   0% /sys/firmware
tmpfs           378G     0  378G   0% /sys/devices/virtual/powercap
root@autodl-container-90264f8b69-78974c7f:~/autodl-tmp# echo "当前根目录分区已用资源百分比是 :$(df -h|awk '/\/$/{print $5}')"
当前根目录分区已用资源百分比是 :2%

=======CPU使用率==================
解决思路,参考解决办法
1. 利用top命令,或者 读取该 /proc/cpuinfo cpu资源信息文件
2. 提取cpu空闲率字段
3. 生产服务器,资源一般不会 99.9空闲的,模拟一定的压测
4. 脚本提取资源使用情况,一般是指某一个时间点的快照
日后你要写服务器资源监控脚本,判断一旦cpu使用率超过 85%,立即给运维发邮件,报警。
top -n1 | grep "Cpu(s)" |awk '{print 100-$8}'  # 目前对的
echo  "CPU使用率: $(top -n 1 | awk 'NR==3  {print  100-$8}')%"  # 目前对的
top -n1 | awk 'NR==3{print 100-$8"%"}'  # 目前对的
#### 如上几个答案,都存在top命令动态更新的坑,位置会发生变化。

#### 建议使用如下命令:
echo -e "CPU使用率如下--$(sar -u 1 1|awk 'NR==5{print 100-$NF}')%"
# sar 动态获取服务器的资源使用率,  
# 每隔1秒,获取1个数据
# sar -u 显示所有信息,显示比较齐全
# sar命令是一个优秀的性能检测命令,但是得额外安装,sysstat包

最终服务器信息采集脚本

[root@m-61 ~/part3-shell]#cat show_server_info.sh 
#!/bin/bash
# 采集当前服务器信息的脚本

echo -e " 
当前系统版本是:$(grep -i 'pretty_name' /etc/os-release |awk -F '"' '{print $2}')
当前系统内核版本是:$(uname -r)
当前系统主机名是:$(hostname)
当前系统eth0网卡ip是:$(ifconfig eth0 |awk 'NR==2{print $2}')
当前系统eth1网卡ip是:$(ifconfig eth1 |awk 'NR==2{print $2}')
当前网络环境,对外的公网IP是:$(curl -s ifconfig.me )
当前内存已使用的百分比情况是 :$(free -m | awk 'NR==2{print $3/$2*100}')%
当前根目录分区已用资源百分比是 :$(df -h|awk '/\/$/{print $5}')
CPU使用率如下--$(sar -u 1 1|awk 'NR==5{print 100-$NF}')%
============================================================" >> /tmp/server_info.log

相关命令解释:
在这里插入图片描述
awk 正则匹配中加入 $----匹配以/结尾的行s在这里插入图片描述
在这里插入图片描述

7.常量(了解)

readonly命令

  • 常量在shell中没有严格的语法支持,但是只有约定俗称的写法(全大写),以及通过命令强制性转为常量;在其他数据类型更丰富的语言中,支持设定
  • 普通变量,如name,age(如果age设置为常量,你理解下是什么意思,这种bug,常出现于初级开发的代码中。。)
  • 常量,如月份,是固定的12个月,因此只能设定为无法修改的值,就是常量。
    在这里插入图片描述
[root@m-61 ~/part3-shell]#readonly ZHANGSANFENG_AGE=500
[root@m-61 ~/part3-shell]#set |grep -i zhangsanfeng
ZHANGSANFENG_AGE=500
_=ZHANGSANFENG_AGE
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#ZHANGSANFENG_AGE=600
-bash: ZHANGSANFENG_AGE: readonly variable

8. 数据类型

用于练习,变量计算的.
shell中,统一进行字符串去处理,但是如果变量值是数字形式,依然支持数字的计算玩法。
一种弱类型的,先明确其值,再确定其类型在这里插入图片描述

8.1 shell语言的数据类型介绍

数字类型用法

在这里插入图片描述
在这里插入图片描述

字符串类型用法

注意几种不同类型的引号即可:

  • 单引号,所见即所得
  • 双引号,识别特殊符号,
  • 反引号,用于执行linux命令时,用这个写法
  • 不加引号(不建议这么用,用于写连续的字符串时,才可以这么写)

9、变量数值计算

9.0、基本语法,符号

在这里插入图片描述

9.1、基于命令进行数学计算

以下运算分为两个角度:

  • 直接对数字计算
  • 变量值进行计算
expr[整型计算]

只能进行整型计算在这里插入图片描述
expr并不是很好用,比较麻烦
在这里插入图片描述

①直接对数字计算
在这里插入图片描述
②对变量值进行计算
在这里插入图片描述

expr模式匹配
在这里插入图片描述

实践1–统计yc.jpg字符个数
在这里插入图片描述
在这里插入图片描述

$(())双括号运算,只支持整数运算,效率更高
双小括号,这种符号,也是用于数学计算才使用。
[root@m-61 ~/part3-shell]#echo $(( ${num1} + ${num2}   ))
15

[root@m-61 ~/part3-shell]#echo $(( ${num1} - ${num2}   ))
9

[root@m-61 ~/part3-shell]#echo $(( ${num1} * ${num2}   ))
36

[root@m-61 ~/part3-shell]#echo $(( ${num1} / ${num2}   ))
4
[root@m-61 ~/part3-shell]## 看懂 $((变量计算表达式)) 写法

$[]

建议用这个写法,比较直观,易懂


[root@m-61 ~/part3-shell]#echo "计算结果是:$[ $num1 + $num2 ]"
计算结果是:15

[root@m-61 ~/part3-shell]#echo "计算结果是:$[ $num1 - $num2 ]"
计算结果是:9

[root@m-61 ~/part3-shell]#echo "计算结果是:$[ $num1 * $num2 ]"
计算结果是:36

[root@m-61 ~/part3-shell]#echo "计算结果是:$[ $num1 / $num2 ]"
计算结果是:4

[root@m-61 ~/part3-shell]#echo "计算结果是:$[ $num1 / $num2 * 8 ]"
计算结果是:32

[root@m-61 ~/part3-shell]#echo "计算结果是:$[ $num1 / $num2 * 8 + 3*2 ]"   
计算结果是:38
let[配合$[]使用,接受变量计算的结果]
计算命令
语法如下

let  结果变量=变量1 运算符 变量2

不得有任何得空格,得连起来写


[root@m-61 ~/part3-shell]#let  result=${num1}+${num2}
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#let  result2=${num1}-${num2}
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#let  result3=${num1}*${num2}
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#let  result4=${num1}/${num2}
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#echo $result  $result2 $result3  $result4
15 9 36 4
bc命令计算变量的数据[类似于let,只不过这里是通过管道接受结果的值]

提示:
整数的计算,用双小括号,let,expr
带有小数的计算,用bc :echo 4.5-1.1|bc

[root@m-61 ~/part3-shell]#echo $num1+$num2 |bc
15
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#echo "$num1 - $num2" |bc
9
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#echo "$num1 *  $num2" |bc
36
[root@m-61 ~/part3-shell]#
[root@m-61 ~/part3-shell]#echo "$num1 /  $num2" |bc
4

BC案例
在这里插入图片描述

seq
seq(sequence 的缩写)是 Linux 中一个用于打印数字序列的命令行工具。它可以生成从某个起始值到结束值的一系列数字,也可以指定步长。类似于python的range。

  • 完整语法格式如下:
    在这里插入图片描述

tr

  • tr 是 translate(转换)的缩写,是一个用于字符替换或删除的命令行工具。它只能处理标准输入(stdin),不能直接操作文件

在这里插入图片描述
在这里插入图片描述

xargs
xargs 是一个将标准输入(stdin)中的内容转换成命令参数并执行的工具。(将标准输入的内容按空格或换行分割后作为参数传递给另一个命令执行。)
在这里插入图片描述
在这里插入图片描述
高级用法详解
在这里插入图片描述

awk

在这里插入图片描述
在这里插入图片描述

9.2、变量练习题

1、根据系统时间打印出,今天、明天的时间; 至少3种写法,用上述的3种数学计算命令即可

[root@m-61 ~/part3-shell]#echo "今天是 $(date +%d) 号"
今天是 23# 外层用 $[] 进行变量的数学计算, 内层用  $( 提取今天的日期 )
[root@m-61 ~/part3-shell]#echo "明天是  $[   $(date +%d)    + 1       ] 号"
明天是  24[root@m-61 ~/part3-shell]#echo "去年是 $[ $(date +%Y) - 1 ] 年"
去年是 2021

提取日期的格式化

[root@m-61 ~/part3-shell]#echo  "当前日期是  $(date +%Y-%m-%d-%T)"
当前日期是  2022-06-23-11:33:54

2.根据系统当前时间,今年还剩下多少个星期

需求拆解,
1. 判断今年还剩下多少天,2. 除以7 不就完事么。


[root@m-61 ~/part3-shell]#echo "今年过去了 $(date +%j) 天"
今年过去了 174[root@m-61 ~/part3-shell]#echo "今年还剩下 $[ 365 - $(date +%j)]天"
今年还剩下 191天

还剩下多少个星期
[root@m-61 ~/part3-shell]#echo "今年还剩下 $[ (365 - $(date +%j)) / 7 ] 个星期"
今年还剩下 27 个星期

9.3、简易版计算机开发(结合逻辑控制语句后,不断优化该计算器版本)

方案1,交互式接收用户输入:用read命令去写,更像计算器

#!/bin/bash
read -p "please input first num:"  num1
read -p "please input sign :"  sign 
read -p "please input second num:" num2

# 计算结果,使用数学计算表达式  $[ ]
echo "计算结果是:$[ ${num1} ${sign}  ${num2}    ]"

方案1,位置参数去写代码

#!/bin/bash
# 计算结果,使用数学计算表达式  $[ ]
echo "计算结果是:$[ ${1} ${2}  ${3}    ]"