
SHELL脚本编程基础
SHELL脚本编程基础
一、SHELL脚本基础
1.shell脚本
包含一些命令或声明,并符合一定格式的文本文件
2.执行shell脚本的方法
bash **.sh
chmod +x **.sh 给脚本加执行权限后使用绝对路径或相对路径运行
给脚本加执行权限后,将脚本所在路径加入$PATH,输入脚本名直接执行
例如:vim /etc/profile.d/env.sh
PATH = /data/script/:$PATH
cat **.sh | bash
3.格式要求
首行shebang机制
在脚本的首行加入#!/bin/bash
4.变量
变量类型:
- 字符
- 数值:整形、浮点型
bash是动态编译语言,不用事先声明,可随时改类型
bash为弱类型语言,运行时会隐式做数据类型转换。无须指定类型,默认为字符型;参与运算会自动进行隐式类型转换,bash不支持浮点数
命名规则:
- 不能使用程序中的保留字,如if,for
- 只能使用数字、字母及下划线,且不能以数字开头
- 见名知义
- 统一命名规则:驼峰命名法
- 建议命名规则:
- 变量名大写
- 局部变量小写
- 函数名小写
- 用英文名字,并体现出实际作用
变量种类:
局部变量:生效范围为当前shell进程;对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效
环境变量:生效范围为当前shell进程即其子进程
本地变量:生效范围为当前shell进程中某代码片段,通常指函数
位置变量:$1,$2…..来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数
特殊变量:
$0 脚本本身的名字
$* 所有参数,全部参数合为一个字符串
$@ 所有参数,每个参数为独立字符串
$# 参数的个数
$? 上一条命令退出时的返回值,判断命令是否执行成功
- 0 为成功
- 1-255 错误
- 也可以在脚本中以exit num 指定命令退出时的返回值
1
2ping -c1 192.168.37.6 &> /dev/null
echo $?
set – 清空所有位置变量
局部变量
变量赋值: name= ‘value’
可以使用引用value
可以是直接字符串: name = “root”
变量引用:name = “$USER”
命令引用:name= `COMMAND`
name=$(COMMAND)
变量引用:${name} 或者 $name
- “ “ 弱引用,其中的变量引用会被替换为变量值
- ‘ ‘ 强引用,其中的变量引用不会被替换为变量值,而保持字符串
显示已定义的所有变量: set
删除变量: unset name
环境变量
声明、赋值:
- export name=VALUE
- declare -x name=VALUE
变量引用:
$name,${name}
显示所有环境变量:
- env
- printenv
- export
- declare -x
删除变量:unset name
bash内建的环境变量:
- PATH
- SHELL
- USER
- UID
- HOME
- PWD
- SHLVL
- LANG
- HOSTNAME
- HISTSIZE
- _ 下划线 (上一条命令的最后一条参数)
小括号的妙用:
只作用于子shell(小括号会开一个子进程)和括号内的命令,而对其父shell及括号外的赋值和命令无影响
例如:
1
2
3
4
5
6TITLE=ceo
(echo $TITLE;TITLE=coo;echo $TITLE)
ceo
coo
ehco $TITLE
ceo
5.算术运算
5.1bash中的算术运算:
+,-,*,/,%取余,**乘方,乘法符号在有些场景中需要转义
实现算术运算:
let var=算术表达式
var=$[算术表达式]
var=$((算术表达式))
var=$(expr arg1 arg2 arg3 …)
此时相当于调用expr命令,算术表达式中的每个元素相当于expr命令的参数,所以必须都要有空格,而且*需要转义
1
2
3[root@centos8 ]#a=$(expr 2 \* 3)
[root@centos8 ]#echo $a
6declare -i var= 数值 (即将var声明为整数)
echo ‘算术表达式’ | bc
5.2bash有内建的随机数生成器变量:$RANDOM(0-32767)
例如:生成0-49之间随机数
echo $[$RANDOM%50](即对50作取余运算)
5.3短路与 短路或
短路与:cmd1 && cmd2 :
- 如果cmd1执行成功,执行cmd2
- 如果cmd1执行失败,不再执行cmd2
短路或:cmd1 || cmd2:
如果cmd1执行成功,不再执行cmd2
如果cmd1执行失败,执行cmd2
示例:
1 | [root@centos8 ~]#x=hello |
上述示例的说明:
test为条件测试命令
$x = $y等号两侧必须有空格,否则就成了赋值
cmd1 && cmd2 || cmd3的逻辑为:如果cmd1成功,则执行cmd2;
如果cmd1不成功,不用执行cmd2,但这时cmd1 && cmd2也就整体不成功,就需要执行cmd3
test等价于[ ],注意中括号和里面的表达式之间要有空格
[[ ]] 双中括号可以在表达式中使用正则表达式,且为扩展的正则表达式
此时要使用 =~ (表示包含的意思) ,即左侧的字符串是否被右侧的pattern所匹配,例如:
1
2#str=gooood;[[ $str =~ o{2,} ]] && echo true
true1
2
3
4
5
6#判断n是否为数字
#n=123;[[ $n =~ ^[[:digit:]]+$ ]] && echo true
true
#判断是否为.sh为后缀的文件
#FILE=f.sh;[[ $FILE =~ \.sh$ ]] && echo true
true
5.3数字的比较
- -eq 等于
- -ne 不等于
- -lt 小于
- -le 小于等于
- -gt 大于
- -ge 大于等于
5.4判断文件
-a 或者 -e, 判断文件是否存在,例如:
1
FILE=/data/test.txt;[ -a "$FILE" ] || touch $FILE
-x 是否可执行
-r 是否可读
-w 是否可写
示例:是否可读并且可写
1
[ -r "$FILE" -a -w "$FILE"]
6 read命令
读入标准输入赋值给变量(注意变量不要加$)
-p 指定要显示的提示
-s 静默输入,一般用于密码
-n N 指定输入的字符长度N
-d ‘字符’ 输入结束符
-t N timeout为N秒
例如:
1 | echo -e "please input your name:\c" |
上例用echo -e 以及\c 目的是不要产生换行,更符合习惯
其实,read本身就有-p选项,可以实现提示功能:
1 | read -p "please input your name:" name |
实现鸡兔同笼问题小脚本:
1 | read -p "请输入头的数量:" head |
7.条件判断
7.1单分支
1 | if 判断条件;then |
7.2双分支
1 | if 判断条件;then |
7.3多分支
1 | if 判断条件;then |
示例:
1 | read -p "input your age:" AGE |
7.4 case语句
1 | case 变量引用 in |
示例,判断输入的是yes还是no
1 | read -p "请输入是否:" INPUT |
上例也可以简化如下:
1 | read -p "请输入yes或no: " INPUT |
8.bash如何展开命令行
- 把命令行分成单个命令词
- 展开别名
- 展开大括号的声明{}
- 展开波浪符的声明 ~
- 命令替换$() 和` `
- 再次把命令行分成命令词
- 展开文件通配符(*、?、[abc]等)
- 准备I/O重定向
- 运行命令
9.bash的配置文件
按生效范围划分,存在两类:
全局配置
- /etc/profile
- /etc/profile.d/*.sh
- /etc/bashrc
个人配置
- ~/.bash_profile
- ~/.bashrc
shell登录的两种方式:
交互式登录
- 直接通过终端输入账号密码登录
- 使用su - username 切换的用户
- 执行顺序:/etc/profile –> /etc/profile.d/*.sh –> ~/.bash_profile–>~/.bashrc–>/etc/bashrc
非交互式登录
- su username
- 图形界面下打开终端
- 执行脚本
- 任何其他的bash实例
- 执行顺序:/etc/profile.d/*.sh –> /etc/bashrc –> ~/.bashrc
profile类:为交互式登录的shell提供配置
- 全局:/etc/profile /etc/profile.d/*.sh
- 个人: ~/.bash_profile
- 功能:用于定义环境变量、运行命令或脚本
bashrc类:为非交互式和交互式登录的shell提供配置
- 全局:/etc/bashrc
- 个人:~/.bashrc
- 功能:用于定义别名和函数、定义本地变量
10.set命令
$- 变量(可以用echo $-查看)
- h:hashhall,打开这个选项后,shell会将命令所在路径hash下来,避免每次都要查询.set +h将选项关闭,set -h 开启
- i:包含这个选项说明当前的shell是个交互式shell。在脚本中,i选项是关闭的
- m:打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行
- B:大括号扩展。比如启用echo {a..z}
- H:该选项打开,可以通过!感叹号来完成历史命令调用,例如!!返回上一条命令,!n 返回第n条历史命令
在工作中强烈建议在脚本中加入以下命令:
set -u : 在扩展一个没有设置的变量时,显示错误信息,等同于set -o nounset.在脚本中使用该命令可以避免安全风险,比如:
1
2
3set -u
Dir=/data
rm -rf $DIR/*上述脚本假设没有开启set -u , DIR是个不存在的变量,会被解析成空,将导致直接将根目录下的所有文件删除
set -e : 如果某个命令执行错误,直接整个脚本退出