Shell脚本编程基础
1. Shell简介
1.1 什么是Shell
- 概念: Shell即使一种命令语言,也是一个用C语言编写的程序(命令解析器)。
- 作用: 主要提供一个借口使用户与内核交操作。
-
流程: 接受用户输入的命令并且进行解释(转换为计算机可以理解的机器码),然后将命令送入内核去执行,最后将结果返回给用户。
Linux系统结构.png
1.2 Shell的种类
- 含义:不同的命令解析器(程序不断升级)
- 区别:提示符不同、语法不同、展示效果不同等
- 常用:sh、csh、ksh、bash等
sh (Bourne Shell) AT&T Bell实验室的Steve Bourne开发 (最早的)
csh (C Shell) 加州伯克利大学的Bill Joy (更强)
ksh (Korn Shell) AT&T Bell实验室的David Korn开发 (升级)
bash(Bourne Again Shell) 自由软件基金会(GNU)开发的一个Shell (统一)
- 常见命令:
命令 | 含义 |
---|---|
cat /etc/shells | 查看系统支持的shell类型 |
echo $SHELL | 查看当前使用的shell类型 |
useradd [参数] 用户名(-g 指定用户组,-c 备注,-s 登录执行的命令,-d 家目录) | 用户添加 |
usermod 参数 用户名(以上四个 + -l 改名) | 用户编辑 |
userdel 用户名 | 用户删除 |
passwd 用户名 | 修改密码 |
例如:修改test用户的登录执行命令种类为bash
sudo usermod -s /bin/bash test1
2. Shell脚本
除了挨个执行命令外,还一个创建一个脚本文件批量处理。
创建脚本并执行的步骤:
- 创建一个脚本文件并用vi模式打开:
vi test.sh
# 可以不加后缀
- 指定运行脚本文件的命令解析器类型,在脚本文件中写入代码:
#!/bin/bash
# 指定为bash类型
- 写入要执行的代码:
echo hello
# 输出字符串hello
- 执行脚本语法:
编号 | 方法 |
---|---|
方法1 | sh 路径及文件名(推荐) |
方法2 | /bin/bash 路径及文件名 |
方法3 | source 路径及文件名 |
方法4 | . 路径及文件名.sh |
3. Shell变量
3.1 本地变量
- 概念:只对当前shell进程有效(ps. 对当前进程的子进程和其它shell进程无效)
- 语法:
设置:变量名=变量值(等号不能有空格)
删除:unset 变量名
输出:echo $变量名
MacBook-Pro:~ test$ VAR_T1=123 #定义变量
MacBook-Pro:~ test$ echo $VAR_T1 #输出变量
123
MacBook-Pro:~ test$ echo ${VAR_T1}456 #输出变量,添加{}避免混淆
123456
MacBook-Pro:~ test$ unset VAR_T1 #删除变量
MacBook-Pro:~ test$ echo $VAR_T1
3.2 环境变量
- 概念:对当前shell进程和子进程有效,其他shell进程无效。通过修改配置文件,可以定义全局都生效的环境变量。
- 语法:
export 变量名=变量值
对所有shell进程都生效:
vi /etc/profile #在该配置文件中定义环境变量
source /etc/profile #让新建立的环境变量立刻生效无需重新启动系统
3.3 局部变量
- 概念:函数调用时创建、调用完毕时销毁。
- 语法:
local 变量名=变量值
MacBook-Pro:~ test$ function a(){
> local VAR_T2=123
> echo $VAR_T2
> }
MacBook-Pro:~ test$ a
123
MacBook-Pro:~ test$ echo $VAR_T2
3.4 位置变量
- 概念:指程序运行时动态传入的参数。
- 语法:
传参:sh 路径及文件名.sh 参数1 ... 参数n
输出:echo $1 / .. / echo $n
MacBook-Pro:shell test$ cat test3.sh
#!/bin/bash
echo $[${1}+${2}] #算数代换
MacBook-Pro:shell test$ sh test3.sh 5 5
10
3.5 特殊变量
- 特殊变量的介绍
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名 |
$n | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数。 |
$@ | 传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会讲到。 |
$? | 上个命令的退出状态,或函数的返回值。 |
$$ | 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。 |
- 特殊变量的应用场景
变量 | 应用场景 |
---|---|
$n | 根据传递的参数安装指定软件 |
$$ | 脚本执行时输出进程编号便于卡死时结束进程(注:sleep 秒数) |
3.6 其他
3.6.1 命令代换
- 概念:通过语法反引号或$(名称)实现先解析shell指令,再赋值给变量。
- 示例:
MacBook-Pro:shell test$ VARDATE=date
MacBook-Pro:shell test$ echo $VARDATE
date
MacBook-Pro:shell test$ VARDATE=`date`
MacBook-Pro:shell test$ echo $VARDATE
2018年10月29日 星期一 20时12分00秒 CST
MacBook-Pro:shell test$ VARDATE=$(date)
MacBook-Pro:shell test$ echo $VARDATE
2018年10月29日 星期一 20时12分14秒 CST
3.6.2 算术代换
- 概念:通过$(()) 或 $[]实现运算功能。
- 示例:
MacBook-Pro:shell test$ echo 8 + 2
8 + 2
MacBook-Pro:shell test$ echo $[8 + 2]
10
4. Shell流程控制(判断)
4.1. 条件测试
- 说明:通过test或 [] 可以测试一个条件是否成立。
- 语法:
语法:test 值1 条件 值2
或
语法: [ 值1 条件 值2 ]
脚下留心:0-代表结果成立,1-代表结果不成立;中括号内部两端必须加空格
- 数值测试:
参数 | 说明 |
---|---|
-eq | 等于则为真 |
-ne | 不等于则为真 |
-gt | 大于则为真 |
-ge | 大于等于则为真 |
-lt | 小于则为真 |
-le | 小于等于则为真 |
- 文件测试:
参数 | 说明 |
---|---|
-e 文件名 | 文件存在则为真 |
-r 文件名 | 文件存在且可读则为真 |
-w 文件名 | 文件存在且可写则为真 |
-x 文件名 | 文件存在且可执行则为真 |
-s 文件名 | 文件存在且至少有一个字符则为真 |
-d 文件名 | 文件存在且为目录则为真 |
-f 文件名 | 文件存在且为普通文件则为真 |
- 字符串测试:
参数 | 说明 |
---|---|
= | 相等则为真 |
!= | 不相等则为真 |
4.2. if...elif...else语句
- 语法:
if 条件1
then
命令1
elif 条件2
then
命令2
else
命令3
fi
- 示例1:判断成绩(>=90优秀,>=80良好,>=60及格,>=0不及格):
#!/bin/bash
#接受分数
SCORE=$1
#判断
if [ $SCORE -ge 90 ]
then
echo "优秀"
elif [ $SCORE -ge 80 ]
then
echo "良好"
elif [ $SCORE -ge 60 ]
then
echo "及格"
elif [ $SCORE -ge 0 ]
then
echo "不及格"
else
echo "分数不合法"
fi
- 示例2:判断当前执行脚本是否是root用户:
#!/bin/bash
WHO=$(whoami)
if [ $WHO != 'root' ]
then
echo "Error: You must be root to run this script!"
exit 1
fi
4.3. case语句
- 语法:
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
....
*)
如果以上都不成立,则执行此程序
;;
esac
-
需求:执行脚本让用户输入
yes - installing...
no - skip
其他 - Please enter the correct option
#!/bin/bash
read -p "Please Input yes/no: " Select_Id
case $Select_Id in
"yes")
echo 'installing...'
;;
"no")
echo 'skip'
;;
*)
echo 'Please enter the correct option'
;;
esac
5. Shell循环
5.1 for循环
- 语法:
for 变量名 in 值1 ... 值N
do
命令
done
- 示例1:输出6个数
#!/bin/bash
for i in 1 2 3 4 5 6
do
echo $i
Done
- 示例2:输出指定目录下得所有文件名
#!/bin/bash
cd $1
filenames=$(ls)
for name in $filenames
do
echo $name
done
5.2 while循环
- 语法:
while 条件
do
命令
done
- 示例1:输出1-10
#!/bin/bash
i=1
while [ $i -le 10 ]
do
echo $i
i=$(($i+1))
done
6. 计划任务
6.1. 简介
- 概念:约定时间执行指定任务(或执行指定脚本文件)
- 举例1:通过计划任务定时发布文章
- 举例2:通过计划任务凌晨3点将测试服务器项目代码同步到线上服务器
6.2. 使用
- 步骤1:通过命令【crontab -e】编写计划任务
- 步骤2:按【i】键编写,最后按【esc】【:wq】保存并退出
多学一招:crontab -e语法同vi编辑器命令 (-e edit缩写)
通过crontab -l 可以查看已有的任务 (-l list缩写)
通过crontab -r 可以移除已有的任务 (-r remove缩写)
6.3. 语法
* * * * * 任务
分 时 日期 月 星期几
项目 | 含义 | 范围 |
---|---|---|
第一个“*” | 一小时中的第几分钟 | 0-59 |
第二个“*” | 一天中的第几小时 | 0-23 |
第三个“*” | 一月中的第几天 | 1-31 |
第四个“*” | 一年中的第几天 | 1-12 |
第五个“*” | 一周中的星期几 | 0-7(0和7代表星期天) |
特殊符号 | 含义 |
---|---|
* | 代表任何时间。比如第一个“*”就代表一小时中的没分钟都执行一次 |
, | 代表不连续的时间,比如“0 8,12,16 * * *”就代表在每天的8点0分,12点0分,16点0分都执行一次命令 |
- | 代表连续的时间范围。比如“0 5 * * 1-6”代表在周一到周六的凌晨5点0分执行命令 |
*/n | 代表每隔多久执行一次。比如“*/10 * * * *”,代表每隔10分钟就执行一遍命令 |
- 例子:每分钟向tmp.txt文件中写入数字6:
*/1 * * * * echo 9 >> /tmp.txt
其他案例:
时 间 | 含义 |
---|---|
45 22 * * * | 在每天22点45分执行命令 |
0 17 * * 1 | 每周1的17点0分执行命令 |
0 5 1,15 * * | 每月1号和15号的凌晨5点0分执行命令 |
40 4 * * 1-5 | 每周一到周五的凌晨4点40分执行命令 |
*/10 4 * * * | 每天的凌晨4点,每个10分钟执行一次命令 |
0 0 1,15 * 1 | 每月1号和15号,每周一的0点0分执行命令,注意:星期几和几号最好不要同时出现,因为他们定义的都是天,非常容易让管理员混乱 |