Shell脚本入门
[TOC]
什么是Shell脚本(shell script)?
Shell和Shell脚本的概念
shell是一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
例如Widnows上的powershell和cmd,Linux上的Bash
我们可以将多个shell命令放入特定拓展名的文件中作为程序执行,这些文件被称作shell脚本。
举个例子
每隔十秒,输出当前date到控制台
1 | #!/bin/sh |
- 第一行 指定脚本解释器,这里是用/bin/sh作解释器
- 第二行 循环条件
- 第三行 循环体开始
- 第四行 睡眠1s
- 第五行 按照特定格式输出 date
- 第六行 循环体结束
echo sleep是系统自带的程序 while do done是shell脚本语言关键字
环境
shell编程跟java,php编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
Linux默认安装了shell解释器bash.
高级编程语言
理论上讲,只要一门语言提供了解释器(而不仅是编译器),这门语言就可以胜任脚本编程,常见的解释型语言都是可以用作脚本编程的,如:Perl、Tcl、Python、PHP、Ruby。Perl是最老牌的脚本编程语言了,Python这些年也成了一些linux发行版的预置解释器。
编译型语言,只要有解释器,也可以用作脚本编程,如ava有第三方解释器Jshell,Ada有收费的解释器AdaScript。
如下是一个Python3 Script示例(假设文件名叫test.py):
1 | #!/usr/bin/python3 |
执行:
1 | python3 test.py |
或者:
1 | chmod +x test.php |
如何选择shell编程语言
熟悉 vs 陌生
如果你已经掌握了一门编程语言(如PHP、Python、Java、JavaScript),建议你就直接使用这门语言编写脚本程序,虽然某些地方会有点啰嗦,但你能利用在这门语言领域里的经验(单元测试、单步调试、IDE、第三方类库)。
新增的学习成本很小,只要学会怎么使用解释器(Jshell、AdaScript)就可以了。
简单 vs 高级
如果你觉得自己熟悉的语言(如Java)写脚本实在太啰嗦,你只是想做一些备份文件、安装软件、下载数据之类的事情,学着使用sh,bash会是一个好主意。
shell只定义了一个非常简单的编程语言,所以,如果你的脚本程序复杂度较高,或者要操作的数据结构比较复杂,那么还是应该使用Python、Perl这样的脚本语言,或者是你本来就已经很擅长的高级语言。因为sh和bash在这方面很弱,比如说:
- 它的函数只能返回字串,无法返回数组
- 它不支持面向对象,你无法实现一些优雅的设计模式
- 它是解释型的,一边解释一边执行,连PHP那种预编译都不是,如果你的脚本包含错误(例如调用了不存在的函数),只要没执行到这一行,就不会报错
环境兼容性
如果你的脚本是提供给别的用户使用,使用sh或者bash,你的脚本将具有最好的环境兼容性,perl很早就是linux标配了,python这些年也成了一些linux发行版的标配,至于mac os,它默认安装了perl、python、ruby、php、java等主流编程语言。
第一个shell脚本
编写
打开文本编辑器,新建一个文件,拓展名为sh(sh代表shell),拓展名并不影响脚本执行,见名知意就好
输入一些代码,第一行一般是这样
1 |
“#!”是一个约定的标记,他告诉shell应用程序这个脚本需要什么解释器来执行。
运行
运行shell脚本有两种方式
作为可执行程序
1
2chmod +x test.sh
./test.sh注意,一定要写成./test.sh,而不是test.sh,运行其它二进制的程序也一样,直接写test.sh,linux系统会去PATH里寻找有没有叫test.sh的,而只有/bin, /sbin, /usr/bin,/usr/sbin等在PATH里,你的当前目录通常不在PATH里,所以写成test.sh是会找不到命令的,要用./test.sh告诉shell说,就在当前目录找。
通过这种方式运行bash脚本,第一行一定要写对,好让shell查找到正确的解释器。
一个使用/bin/sh作为解释器的脚本是可以省去第一行的
作为解释器参数
这种运行方式是,直接在shell中运行解释器,其参数就是shell脚本的文件名,如
1
2/bin/sh test.sh
/usr/bin/python test.py这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。
Shell脚本语法
变量
定义变量
定义变量时,变量名不加美元符号($)
1 | your_name="tux" |
注意,变量名和等号之间不能有空格
使用变量
使用一个定义过的变量,只要在变量名前面加美元符号即可,如:
1 | your_name="qinjx" |
变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:
1 | for skill in Ada Coffe Action Java; do |
如果不给skill变量加花括号,写成echo “I am good at $skillScript”,解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。
推荐给所有变量加上花括号,这是个好的编程习惯。IntelliJ IDEA编写shell script时,IDE就会提示加花括号。
重定义变量
已定义的变量,可以被重新定义,如:
1 | your_name="tux" |
这样写是合法的,但注意,第二次赋值的时候不能写$your_name=”linux”,使用变量的时候才加美元符。
注释
以”#”开头的行就是注释,会被解释器忽略,sh里没有多行注释,只能每一行加一个#号。
如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。
字符串
字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了,哈哈),字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似。
单引号
1 | str='this is a string' |
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
- 单引号字串中不能出现单引号(对单引号使用转义符后也不行)
双引号
1 | your_name='qinjx' |
- 双引号里可以有变量
- 双引号里可以出现转义字符
字符串操作
拼接字符串
1 | your_name="qinjx" |
获取字符串长度:
1 | string="abcd" |
提取子字符串
1 | string="alibaba is a great company" |
查找子字符串
1 | string="alibaba is a great company" |
条件判断
if else
- if
1 | if condition |
写成一行(适用于终端命令提示符):
1 | if `ps -ef | grep ssh`; then echo hello; fi |
末尾的fi就是if倒过来拼写,后面还会遇到类似的
- if else
1 | if condition |
- if else-if else
1 | if condition1 |
流程控制
for
1 | for var in item1 item2 ... itemN |
while
1 | while condition |
无限循环
1 | while : |
或者
1 | while true |
until
1 | until condition |
case
1 | case "${opt}" in |
函数
1 | demoFun(){ |
用户输入
crontab命令
crond是linux下用来周期性地执行某种任务或等待处理某些事件的一个守护进程,当安装完操作系统后,默认会安装此服务工具,并且会自动启动crond进程,crond进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。
crontab命令介绍
Linux下的任务调度分为两类,系统任务调度和用户任务调度
系统任务调度 系统周期性所要执行的工作,比如写缓存数据到硬盘、日志清理等。在/etc目录下有一个crontab文件,这个就是系统任务调度的配置文件。
/etc/crontab文件包含下面几行
第一行SHELL变量指定了系统要使用哪个shell,这里是bash,第二行PATH变量指定了系统执行命令的路径.
用户任务调度 用户定期要执行的工作,比如用户数据备份、定时邮件提醒等。用户可以使用 crontab 工具来定制自己的计划任务。所有用户定义的crontab 文件都被保存在 /var/spool/cron/crontabs目录中。其文件名与用户名一致。
用户所建立的crontab文件中,每一行都代表一项任务,每行的每个字段代表一项设置,它的格式共分为六个字段,前五段是时间设定段,第六段是要执行的命令段,格式如下:
minute hour day month week command
其中:
minute: 表示分钟,可以是从0到59之间的任何整数。
hour:表示小时,可以是从0到23之间的任何整数。
day:表示日期,可以是从1到31之间的任何整数。
month:表示月份,可以是从1到12之间的任何整数。
week:表示星期几,可以是从0到7之间的任何整数,这里的0或7代表星期日。
command:要执行的命令,可以是系统命令,也可以是自己编写的脚本文件。
在以上各个字段中,还可以使用以下特殊字符:
星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。
逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”
中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”
正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。
crond服务
1 | # 大部分Linux发行版默认已安装,如果未安装crontab |
crontab命令详解
1.命令格式:
crontab [-u user] file
crontab [-u user][ -e | -l | -r ]
2.命令功能:
通过crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script脚本。时间间隔的单位可以是分钟、小时、日、月、周及以上的任意组合。这个命令非常设合周期性的日志分析或数据备份等工作。
3.命令参数:
-u user:用来设定某个用户的crontab服务,例如,“-u ixdba”表示设定ixdba用户的crontab服务,此参数一般有root用户来运行。
file:file是命令文件的名字,表示将file做为crontab的任务列表文件并载入crontab。如果在命令行中没有指定这个文件,crontab命令将接受标准输入(键盘)上键入的命令,并将它们载入crontab。
-e:编辑某个用户的crontab文件内容。如果不指定用户,则表示编辑当前用户的crontab文件。
-l:显示某个用户的crontab文件内容,如果不指定用户,则表示显示当前用户的crontab文件内容。
-r:从/var/spool/cron目录中删除某个用户的crontab文件,如果不指定用户,则默认删除当前用户的crontab文件。
-i:在删除用户的crontab文件时给确认提示。
4.常用方法:
- 创建一个新的crontab文件
在考虑向cron进程提交一个crontab文件之前,首先要做的一件事情就是设置环境变量EDITOR。cron进程根据它来确定使用哪个编辑器编辑crontab文件。9 9 %的UNIX和LINUX用户都使用vi,如果你也是这样,那么你就编辑$ HOME目录下的. profile文件,在其中加入这样一行:
1 | EDITOR=vi; |
然后保存并退出。
crontab mycron
- 列出crontab文件
crontab -l
编辑crontab文件
如果希望添加、删除或编辑crontab文件中的条目,而E D I TO R环境变量又设置为v i,那么就可以用v i来编辑crontab文件,相应的命令为:
crontab -e
可以像使用v i编辑其他任何文件那样修改crontab文件并退出。如果修改了某些条目或添加了新的条目,那么在保存该文件时, c r o n会对其进行必要的完整性检查。如果其中的某个域出现了超出允许范围的值,它会提示你。
- 删除crontab文件
要删除crontab文件,可以用:
`` crontab -r``
- 恢复丢失的crontab文件
crontab <filename>
其中,
用户crontab文件示例