1.8 linux基础(八)-shell脚本基础
1.8 linux基础(八)-shell脚本基础
- 1.8 linux基础(八)-shell脚本基础
- 1.8.1、创建shell脚本
- 1.8.2 脚本的执行方式
- 1.8.3、脚本规范
- 1.8.4 脚本调试
- 1.8.5 养成脚本编写的好习惯
- 1.8.6 编写第一个脚本hello world
- 1.8.7 写一个脚本脚本/root/bin/systeminfo.sh,显示当前主机系统信息
- 1.8.8 变量
- 1.8.9 $?命令执行状态返回值(退出状态)
- 1.8.10 退出状态码
- 1.8.11 算术运算
- 1.8.12 逻辑运算
- 1.8.13 条件测试
- 1.8.14 测试命令
- 1.8.15 bash的数值测试
- 1.8.16 bash的字符串测试
- 1.8.17 Bash的文件测试
- 1.8.18 使用read命令来接受输入
- 1.8.19 bash的配置文件
- 1.8.20 shell登录两种方式
- 1.8.21 Bash 退出任务
- 1.8.22 $-变量
1.8.1、创建shell脚本
- 使用文本编辑器vim来创建文本文件
- 第一行必须包括shell声明序列:#!(幻数)
- #!/bin/bash
- 添加注释,注释以#开头 (尽量不要用中文)
1.8.2 脚本的执行方式
- bash script-name.sh
- /path/to/script-name.sh或者 ./script-name.sh 脚本需要有执行权限才行
给脚本增加执行权限:
chmod +x script-name.sh
- source或. script-name
- 注意:会将脚本中的变量值或函数返回值传递到父shell中,会在当前shell中执行加载脚本中的变量命令,而不是产生子shell去执行脚本。a,b都是产生子shell执行的脚步。
[root@CentOS7 data]# cat source.sh
#!/bin/bash
#
name=10000
[root@CentOS7 data]# name=0
[root@CentOS7 data]# echo $name
0
[root@CentOS7 data]# sh source.sh
[root@CentOS7 data]# echo $name
0
[root@CentOS7 data]# . source.sh
[root@CentOS7 data]# echo $name
10000
[root@CentOS7 data]# cat source2.sh
echo $name
[root@CentOS7 data]# . source2.sh
10000 ##一个脚本调用另一个脚本的参数
1.8.3、脚本规范
脚本代码开头约定
1、第一行一般为调用使用的语言
2、程序名,避免更改文件名为无法找到正确的文件
3、版本号
4、更改后的时间
5、作者相关信息
6、该程序的作用,及注意事项
7、最后是各版本的更新简要说明
#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Revision: 1.1
# Date: 2018/08/01
# Author: zhu
# Email: xxx@qq.com
# Website: www.xxx.com
# Description: This is the first script
# ------------------------------------------
# Copyright: 2018 zhu
# License: GPL
echo “hello world
1.8.4 脚本调试
检测脚本中的语法错误bash -n /path/to/some_script
调试分步执行bash -x /path/to/some_scrip
1.8.5 养成脚本编写的好习惯
- 成对符号一次性打出来,然后退格在符号里添加内容,防止遗漏
- []中括号,[[]]两端必须都有两个空格
- 流程控制语句,一次性将格式这写完,在添加内容
- 通过缩进让代码易读
- 常规变量的字符串定义变量值应该加号,并且等号前后不能有空格,需要强引用的,用'',如果是命令的引用,则用双引号""
- linux中的符号都是英文状态下的符号
1.8.6 编写第一个脚本hello world
[root@CentOS7 ~]# vim test1.sh
[root@CentOS7 ~]# cat test1.sh
#!/bin/bash
# ------------------------------------------
# Filename: test1.sh
# Revision: 1.1
# Date: 2018/08/01
# Author: zhu
# Email: 154760531@qq.com
# Website: www.studylinux.net
# Description: This is the first script
# ------------------------------------------
# Copyright: 2018 zhu
# License: GPL
echo "hello world"
1.8.7 写一个脚本脚本/root/bin/systeminfo.sh,显示当前主机系统信息
包括主机名, IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小
[root@CentOS7 ~]# cat /root/bin/systeminfo.sh
#!/bin/bash
echo "OS_version is `cat /etc/centos-release| grep -o "[0-9]\+"|head -n1`"
echo "Kernel_version is `uname -r`"
echo "IPv4 is `ifconfig ens33|grep "cast"|tr -s ' ' |cut -d" " -f3`"
echo "CPU_type is `lscpu |grep "Model name"|tr -s " " |cut -d: -f2`"
echo "Memory Size is `cat /proc/meminfo |head -n1 |tr -d " "|cut -d: -f2`"
lsblk|grep "^sd"|tr -s " "|cut -d " " -f1,4`"
echo "Hostname is $HOSTNAME"
echo "My name is "$USER""
1.8.8 变量
-
变量:命名的内存空间
-
数据存储方式:ASCII
- 字符:110
- 数值:110
-
变量作用:
- 1、数据存储格式
- 2、参与的运算
- 3、表示的数据范围
-
变量类型:
- 字符
- 数值:整型、浮点型
-
强类型:变量在使用前,必须事先声明,甚至还需要初始化
-
弱类型:变量在使用前,不需要事先声明,参与运算会自动进行隐式类型转换。默认为字符形式,bash不支持浮点型。
-
变量命名法则:
- 1、不能使程序中的保留字:例如if, for
- 2、只能使用数字、字母及下划线,且不能以数字开头
- 3、见名知义
- 4、统一命名规则:驼峰命名法
-
根据变量的生效范围等标准划分下面变量类型:
-
局部变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
-
环境(全局)变量:生效范围为当前shell进程及其子进程
-
本地变量:生效范围为当前shell进程中某代码片断,通常指函数
-
位置变量:$1, $2, ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它 的参数
-
特殊变量:$?, $0, $*, $@, $#,$$
-
$$:当前进程的PID
-
$!:执行上一个指令的PID
1.8.8.1 局部变量
- 变量赋值:name=‘value’
- 可以使用引用value:
- (1) 可以是直接字串; name=“root"
- (2) 变量引用:name="$USER"
- (3)命令引用:name=`COMMAND` name=$(COMMAND)
- 变量引用:${name} $name
- "":弱引用,其中的变量引用会被替换为变量值
- '':强引用,其中的变量引用不会被替换为变量值,而保持原字符串
- 显示已定义的所有变量:set
- 删除变量:unset name
1.8.8.2环境变量
- 变量声明、赋值:
- export name=VALUE
- declare -x name=VALUE
- 变量引用:$name, $
- 显示所有环境变量:
- env
- printenv
- export
- declare -x
- 删除变量: unset name
1.8.8.3 只读变量
- 只读变量:只能声明,但不能修改和删除
- 声明只读变量:
- readonly name
- declare -r name
- 查看只读变量: readonly –p
1.8.8.4 位置变量
- 位置变量:在脚本代码中调用通过命令行传递给脚本的参数
- $1, $2, ...:对应第1、第2等参数,
- shift [n]换位置
- $0: 命令本身
- "$*":传递给脚本的所有参数,全部参数合为一个字符串,相当于"$1 $2 $3"
- "$@": 传递给脚本的所有参数,会保留所有的内嵌在每个参数中的任何空白,将所有参数视为不同的独立字符串,相当于"$1" "$2" "$3"
- $#: 传递给脚本的参数的个数
- $@: 传递给脚本的所有参数
- $*: 引用传递给脚本的所有参数,只在被双引号包起来的时候$*和$#才会有差异。
- set -- 清空所有位置变量
[root@CentOS7 ~]# name=parent;{ echo "1:$name";name=son;echo "2:$name"; };echo "3:$name"
1:parent ## 花扩号在当前shell中执行,前后有空格,不开启子shell
2:son
3:son
[root@CentOS7 ~]# name=parent;(echo "1:$name";name=son;echo "2:$name");echo "3:$name"
1:parent ## 小括号在执行时,会开启子进程,子进程能拿到父进程的变量,子进程内变量赋值、内部命令将会影响子进程的环境,()执行完成后,子进程结束,不保留变量赋值。
2:son
3:parent
1.8.9 $?命令执行状态返回值(退出状态)
进程使用退出状态来报告成功或失败
- 0 代表成功 1-255代表失败
- $? 变量保存上一条命令执行状态返回值
- 例如: ping -c1 -W1 hostdown &> /dev/null echo $?
1.8.10 退出状态码
- bash自定义退出状态码
- exit [n]:自定义退出状态码
- 注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命 令后面的数字 注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
1.8.11 算术运算
- bash中的算术运算:bash会对数字执行隐式的类型转换
- 运算操作符:+, -, *, /, %取模(取余), **(乘方)
- 实现算术运算:
- (1) let var=算术表达式
- (2) var=$[算术表达式]
- (3) var=$((算术表达式))
- (4) var=$(expr arg1 arg2 arg3 ...)
- (5) declare –i var = 数值
- (6) echo "算术表达式" | bc
- 乘法符号有些场景中需要转义,如*
- bash有内建的随机数生成器:$RANDOM(0-32767) echo $[$RANDOM%50] :0-49之间随机数
- 增强型赋值: +=, -=, *=, /=, %=
- let varOPERvalue
- 例如:let count+=3 即count=count+3 自加3后自赋值
- 自增,自减:
- let var+=1
- let var++
- let var-=1
- let var--
1.8.12 逻辑运算
- true, false
- 1, 0
- 与:
- 1 与 1 = 1
- 1 与 0 = 0
- 0 与 1 = 0
- 0 与 0 = 0
- 或:
- 1 或 1 = 1
- 1 或 0 = 1
- 0 或 1 = 1
- 0 或 0 = 0
- 非:
- ! 1 = 0
- ! 0 = 1
- 短路运算
- 短路与
- 第一个为0,结果必定为0
- 第一个为1,第二个必须要参与运算
- 短路或
- 第一个为1,结果必定为1
- 第一个为0,第二个必须要参与运算
- 异或:^
- 异或的两个值,相同为假0,不同为真1
1.8.13 条件测试
- 判断某需求是否满足,需要由测试机制来实现
- Note:专用的测试表达式需要由测试命令辅助完成测试过程
- 评估布尔声明,以便用在条件性执行中
- 若真,则返回0
- 若假,则返回1
1.8.14 测试命令
- test EXPRESSION
- [ EXPRESSION ]
- [[ EXPRESSION ]]
- 注意:EXPRESSION前后必须有空白字符
1.8.15 bash的数值测试
- 数值测试:
- -gt 是否大于
- -ge 是否大于等于
- -eq 是否等于
- -ne 是否不等于
- -lt 是否小于
- -le 是否小于等于
1.8.16 bash的字符串测试
- 字符串测试:
-
= 是否等于
-
> ascii码是否大于ascii码
-
< 是否小于
-
!= 是否不等于
-
=~ 左侧字符串是否能够被右侧的PATTERN所匹配
-
注意: 此表达式一般用于[[]]中;扩展的正则表达式,右侧的PATTERN不加引号
-
-z "STRING" 字符串是否为空,空为真,不空为假
-
-n "STRING" 字符串是否不空,不空为真,空为假
-
注意:用于字符串比较时的用到的操作数都应该使用引号
-
[root@CentOS7 ~]# var=abcdef;[[ "$var" = abc* ]] && echo 1 || echo 0
1 ## [[ = ]] 支持通配符
[root@CentOS7 ~]# var=abcdef;[[ "$var" = "abc*" ]] && echo 1 || echo 0
0 ## 引号引起来的都视为是字符串
[root@CentOS7 ~]# filename=a.conf;[[ "$filename" =~ \.conf ]] && echo 1 || echo 0
1 ## 正则表达式不加引号
1.8.17 Bash的文件测试
1.8.17.1 文件存在性测试
- -a FILE:同-e
- -e FILE: 文件存在性测试,存在为真,否则为假
1.8.17.2 文件类别测试
- -b FILE:是否存在且为块设备文件
- -c FILE:是否存在且为字符设备文件
- -d FILE:是否存在且为目录文件
- -f FILE:是否存在且为普通文件
- -h FILE 或 -L FILE:存在且为符号链接文件
- -p FILE:是否存在且为命名管道文件
- -S FILE:是否存在且为套接字文件
1.8.17.2 Bash的文件权限测试
- -r FILE:是否存在且可读
- -w FILE: 是否存在且可写
- -x FILE: 是否存在且可执行
1.8.17.3 文件特殊权限测试:
- -u FILE:是否存在且拥有suid权限
- -g FILE:是否存在且拥有sgid权限
- -k FILE:是否存在且拥有sticky权限
1.8.17.4 Bash的文件属性测试
- 文件大小测试:
- -s FILE: 是否存在且非空
1.8.17.5 文件是否打开:
- -t fd: fd 文件描述符是否在某终端已经打开
- -N FILE:文件自从上一次被读取之后是否被修改过
- -O FILE:当前有效用户是否为文件属主
- -G FILE:当前有效用户是否为文件属组
1.8.17.6 Bash的文件属性测试
- 双目测试:
- FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
- FILE1 -nt FILE2: FILE1是否新于FILE2(mtime) - FILE1 -ot FILE2: FILE1是否旧于FILE2
1.8.17.7 Bash的组合测试条件
- 第一种方式:
- COMMAND1 && COMMAND2 并且
- COMMAND1 || COMMAND2 或者
- ! COMMAND 非
- 如:[[ -r FILE ]] && [[ -w FILE ]]
- 第二种方式:
- EXPRESSION1 -a EXPRESSION2 并且
- EXPRESSION1 -o EXPRESSION2 或者
- ! EXPRESSION 非
- 必须使用测试命令进行
- 示例:
[root@CentOS7 ~]# [ -z "$HOSTNAME" -o $HOSTNAME == "CentOS7.5.zhu.com" ] && echo 1 || echo 0
1
[root@CentOS7 ~]#[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
[root@CentOS7 ~]#[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
# /etc/fstab
# Created by anaconda on Wed Jul 18 17:26:27 2018
1.8.18 使用read命令来接受输入
- 使用read来把输入值分配给一个或多个shell变量
- -p 指定要显示的提示
- -s 静默输入,一般用于密码
- -n N 指定输入的字符长度N
- -d '字符' 输入结束符
- -t N TIMEOUT为N秒
- read 从标准输入中读取值,给每个单词分配一个变量 所有剩余单词都被分配给最后一个变量
- read -p "Enter a filename:" FILE
1.8.19 bash的配置文件
- 按生效范围划分,存在两类:
- 全局配置: /etc/profile /etc/profile.d/*.sh /etc/bashrc
- 个人配置: ~/.bash_profile ~/.bashrc
1.8.20 shell登录两种方式
- 交互式登录:
- (1)直接通过终端输入账号密码登录
- (2)使用“su - UserName” 切换的用户
- 执行顺序:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
- 非交互式登录:
- (1)su UserName
- (2)图形界面下打开的终端
- (3)执行脚本
- (4)任何其它的bash实例
- 执行顺序: ~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
1.8.20.1 Profile类
- profile类:为交互式登录的shell提供配置
-
全局:/etc/profile, /etc/profile.d/*.sh
-
个人:~/.bash_profile
-
功用:
-
(1)用于定义环境变量
-
(2) 运行命令或脚本
-
1.8.20.2 Bashrc类
- bashrc类:为非交互式和交互式登录的shell提供配置
- 全局:/etc/bashrc
- 个人:~/.bashrc
- 功用:
- (1) 定义命令别名和函数
- (2) 定义本地变量
编辑配置文件生效
- 修改profile和bashrc文件后需生效
- 两种方法:
- 1重新启动shell进程
- 2 . 或source
例: . ~/.bashrc
- 让任意一个目录下的具有执行权限的脚本不用输入路径就可以执行。
[root@CentOS7 scripts]# cat /etc/profile.d/zhu.sh
PATH=.:$PATH
[root@CentOS7 scripts]# . /etc/profile.d/zhu.sh
[root@CentOS7 scripts]# yesorno.sh
please input yes or no:y
Your answer is YES.
[root@CentOS7 scripts]# echo $PATH
.:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
tips:为了安全考虑,在生产中不建议这么做
1.8.21 Bash 退出任务
- 保存在~/.bash_logout文件中(用户)
- 在退出登录shell时运行
- 用于创建自动备份
- 清除临时文件
1.8.22 $-变量
- h:hashall,打开这个选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选项关闭
- i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的 shell。所谓的交互式shell,在脚本中,i选项是关闭的(cat /etc/profile.d/vte.sh)
- m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继 续,后台或者前台执行等。
- B:braceexpand,大括号扩展
- H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完 成,例如“!!”返回上最近的一个历史命令,“!n”返回第 n 个历史命令