Linuxshell脚本-格式-变量-条件测试
1、Linuxshell脚本格式
脚本文件名称格式:
1、NAME.sh。脚本文件名称必须以 .sh 结尾
脚本编辑第一行必须包括shell声明序列:#!
添加注释,注释以#开头
2、加3执行权限
给予执行权限,在命令行上指定脚本的绝对或相对路径
3、运行脚本
直接运行解释器,将脚本作为解释器程序的参数运行
示例:
[17:48:44 root@centos8 /data/bashs]#cat hello.sh #!/bin/bash #20220413 #practice echo "hello world"
1.1shell脚本调试
只能检测脚本中的语法错误,但无法检查处命令错误,但不真正执行脚本
调试检查语法 bash -n /path/to/some_script 调试并执行 bash -x /path/to/some_script
总结:脚本错误常见的三种
语法错误,会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行不一定是准确的
命令错误,默认后续的命令还会继续执行,用bash -n 无法检查出来,可以使用bash -x 进行观察
逻辑错误,只能使用bash -x 进行观察
2.变量
变量类型
- 内置变量,如:PS1, PATH, UID, HOSTNAME等
- 用户自定义变量
不同的变量存放的数据不同,决定了以下
- 数据存储方式
- 参与的运算
- 表示的数据范围
变量数据类型:
- 字符
- 数值:整形,浮点型,bash不支持浮点型
2.1.shell变量命名法则
命名要求
- 区分大小写
- 不能使用程序中的保留字和内置变量;如:if,for
- 只能使用数字,字母下划线,且不能以数字开头,注意:不支持短横线“ - ”,和主机名相反
命名习惯
- 见名知义,用英文单词命名,并体现出实际作用,不要简写。
- 变量名大写
- 局部变量小写
- 函数名小写
- 大驼峰StudentNmae
- 小驼峰studentName
- 下划线student_name
2.2变量定义和引用
变量的生效范围等标准划分变量类型
- 普通变量:生效范围为当前shell进程;对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效
- 环境变量:生效范围为当前shell进程及其子进程
- 本地变量:生效范围为当前shell进程中某代码片断,通常指函数
变量赋值 name='value' value (1) 可以是直接字串;name="username" (2) 变量引用:name="$username" (3) 命令引用:name=`COMMAND`, name=$(COMMAND) 注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除 变量引用 $name ${name} " ":弱引用,其中的变量引用会替换为变量值; ' ':强引用,其中的变量引用不会被替换为变量值,而保持原字符串
显示以定义的所有变量
set
删除变量
unset name
2.3环境变量
环境变量:
- 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
- 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
- 一般只在系统配置文件中使用,在脚本较少使用
变量声明和赋值
声明并赋值 export name=VALUE declare -x name=VALUE 或者分两步实现 name= VALUE export name
变量引用:
$name
${name}
显示所有环境变量
env printenv export declare -x 查看指定进程的环境变量 cat /proc/$PID/environ (查看PID pstree -p) 删除变量 unset name bash的内建的环境变量 PATH,SHELL,USER,UID,HOME,PWD等
2.4只读变量
只读变量:只能声明定义,但后续不饿能修改和删除,即常量
声明只读变量:
readonly name decalare -r name
查看只读变量
readonly [-p] declare -r
2.5位置变量
位置变量:在bash shell 中内置的变量,在脚本你代码中调用通过命令行传递给脚本的参数
$1,$2, . . . 对应第1个、第2个等参数,sheft [n]换位置 $0 命令本身,包括路径 $* 传递给脚本的所有参数,全部参数合为一个字符串 $@ 传递给脚本的所有参数,每个参数为独立字符串 $# 传递给脚本的参数个数 注意:$@ $* 只在被双引号包起来的时候才会有差异 清空所有位置变量 set --
2.6推出状态码变量
进程执行后,将变量$?保存状态码的相关数字,不同的值反应成功或失败,$?取值范例0-255
$?的值为0 #代表成功 $?的值是1到255 #代表失败
用户可以在脚本中使用以下命令自行定义推出状态码
exit [n]
注意:
- 脚本中一旦遇到exit命令,脚本会立即终止;终止推出状态取决于exit命令后面的数字
- 如果exit后面无数子,终止退出状态取决于exit命令前面命令执行结果
- 如果没有exit命令,即未给脚本指定推出状态码,整个脚本的推出状态码取决于脚本中执行的最后一条命令的状态码
3.1条件测试命令
条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表示式需要测试命令辅助完成测试过程,实现评估布尔声明,以便使用在条件性环境下进行执行
若真,则状态码变量$?返回0
若假,则状态码变量$?返回1
条件测试命令
- test EXPRESSION
- [ EXPRESSION ] #和test等价,建议使用[ ]
- [[ EXPRESSION ]] 相当于增强版的[ ],支持[ ]的用法,且支持扩展正则表达式和通配符
注意:
EXPRESSION前后必须由空白字符
3.1.1 数值测试
-eq 是否等于 -ne 是否不等于 -gt 是否大于 -ge 是否大于等于 -lt 是否小于 -le 是否小于等于
3.1.2 文件测试
存在性测试
-a FILE:同 -e -e FILE: 文件存在性测试,存在为真,否则为假 -b FILE:是否存在且为块设备文件 -c FILE:是否存在且为字符设备文件 -d FILE:是否存在且为目录文件 -f FILE:是否存在且为普通文件 -h FILE 或 -L FILE:存在且为符号链接文件 -p FILE:是否存在且为命名管道文件 -S FILE:是否存在且为套接字文件
文件权限测试:
-r FILE:是否存在且可读 -w FILE: 是否存在且可写 -x FILE: 是否存在且可执行 -u FILE:是否存在且拥有suid权限 -g FILE:是否存在且拥有sgid权限 -k FILE:是否存在且拥有sticky权限
注意:最终结果由用户对文件的实际权限决定,而非文件属性决定
文件属性测试
-s FILE #是否存在且非空 -t fd #fd 文件描述符是否在某终端已经打开 -N FILE #文件自从上一次被读取之后是否被修改过 -O FILE #当前有效用户是否为文件属主 -G FILE #当前有效用户是否为文件属组 FILE1 -ef FILE2 #FILE1是否是FILE2的硬链接 FILE1 -nt FILE2 #FILE1是否新于FILE2(mtime) FILE1 -ot FILE2 #FILE1是否旧于FILE2
3.2 关于()和 {}
(CMD1;CMD2;...)和 { CMD1;CMD2;...; } 都可以将多个命令组合在一起,批量执行
( list ) 会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境
帮助参看:man bash 搜索(list)
{ list; } 不会启子shell, 在当前shell中运行,会影响当前shell环境
帮助参看:man bash 搜索{ list; }
示例:()和{}
[12:56:47 root@centos8 ~]#name=li;( echo $name;name=yan;echo $name ); echo $name li yan li [12:57:35 root@centos8 ~]#name=li;{ echo $name;name=yan;echo $name; }; echo $name li yan yan [12:57:53 root@centos8 ~]#
[13:00:08 root@centos8 ~]#( cd /data;ls ) bashs f1.txt fstab lianx passwd seq.log system_info.sh test [13:00:15 root@centos8 ~]#pwd /root [13:00:20 root@centos8 ~]#{ cd /data;ls; } bashs f1.txt fstab lianx passwd seq.log system_info.sh test [13:00:26 root@centos8 /data]#pwd /data [13:00:29 root@centos8 /data]#
3.3组合测试条件
3.3.1 第一种方式
[ EXPRESSION1 -a EXPRESSION2 ] 并且,EXPRESSION1和EXPRESSION2都是真,结果才为真 [ EXPRESSION1 -o EXPRESSION2 ] 或者,EXPRESSION1和EXPRESSION2只要有一个真,结果就为 真 [ ! EXPRESSION ] 取反
说明: -a 和 -o 需要使用测试命令进行,[[ ]] 不支持
3.3.2第二种方式
COMMAND1 && COMMAND2 #并且,短路与,代表条件性的AND THEN
如果COMMAND1 成功,将执行COMMAND2,否则,将不执行COMMAND2
COMMAND1 || COMMAND2 #或者,短路或,代表条件性的OR ELSE
如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2
! COMMAND #非,取反
4、使用read命令来接受输入
使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变 量,所有剩余单词都被分配给最后一个变量,如果变量名没有指定,默认标准输入的值赋值给系统内置 变量REPLY
格式
read [options] [name ...] 常见选项: -p 指定要显示的提示 -s 静默输入,一般用于密码 -n N 指定输入的字符长度N -d '字符' 输入结束符 -t N TIMEOUT为N秒
作业练习
9、编写脚本disk.sh,显示当前硬盘分区中空间利用率最大的值
[10:19:53 root@centos8 /data/bashs]#cat disk.sh #!/bin/bash # #Maximum disk space #USAGE 使用率 #DISKINFO=`df -h | grep "$USAGE"` USAGE=`df -h |grep -v "Filesystem" |tr -s ' ' |cut -d' ' -f5 |sort -nr|head -1` DISK=`df -h | grep "$USAGE" | tr -s ' ' | cut -d' ' -f1` SIZE=`df -h | grep "$USAGE" | tr -s ' ' | cut -d' ' -f2` USED=`df -h | grep "$USAGE" | tr -s ' ' | cut -d' ' -f3` AVAIL=`df -h | grep "$USAGE" | tr -s ' ' | cut -d' ' -f4` FDISK=`df -h | grep "$USAGE" | tr -s ' ' | cut -d' ' -f6` echo "diskinfo:" #echo "$DISKINFO" echo "$DISK" echo echo -e "size:$SIZE; userd:\E[1;31m$USED\E[0m; avail:\E[1;32m$AVAIL\e[0m; use%:\E[1;35m$USAGE\e[0m " echo echo -e "\e[1;36mdisk-partition: $DISK\e[0m" echo "File-directory: $FDISK"
10、编写脚本 systeminfo.sh,显示当前主机系统信息,包括:主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小
[17:08:55 root@centos8 /data/bashs]#cat systeminfo.sh #!/bin/bash #systeminfo #20220415 # echo echo "**************************HOST systeminfo*****************************" echo "HOSTNAME: `hostname`" echo "IPADDR: `ifconfig |head -2|tail -1|grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'|head -1`" echo "OSVERSION: `cat /etc/redhat-release`" echo "KERNEL: `uname -r`" echo "CPU: `lscpu | grep "Model name"|tr -s ' '|cut -d":" -f2|head -1`" echo "MEMORY: `free -h | tr -s ' '|grep Mem|cut -d' ' -f2`" echo "DISK `lsblk | grep "^sda"|tr -s ' ' | cut -d" " -f4`" echo "***********************************************************************"