文章目录
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环境。
总结
- 执行一次bash,就单独开辟一个子bash环境
- 执行一次exsit就退出一个bash环境
- 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命令
尝试用命令去完成需求
- ping
- 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`)
但是这俩变量虽说 都是提取所有参数,但是提取之后的数据构造不一样。
重点(记住如下用法即可)
$@
和$*
都用于接收不定长的用户参数- 在脚本中使用这俩特殊变量,必须加上双引号!!!才能发挥其作用!
- 一般都是结合for循环去,找出这俩特殊变量存储的所有元素.
测试脚本:
echo "----------------测试\$*,给变量添加了引号用法--------------"
for v in "$*"
do
echo "传入的位置参数,分别是${v}"
done
echo "----------------测试\$@,添加了引号用法--------------"
for v in "$@"
do
echo "传入的位置参数,分别是${v}"
done
即为:$@的特殊之处–在直接echo变量的值的时,也是将多个参数构造成一个整体;但是如果在for循环中的话,则是能够区分出每一个元素。
变量复习
变量练习题–采集服务器数据
- 采集主机信息,题意
写脚本,提取当前机器的静态属性,包括如下,写入文件/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} ]"