shell脚本学习
一、shell与内核
1.1 Shell名词解释
1、Kernel:Linux内核主要是为了和硬件打交道
2、Shell:
命令解释器
shell是用C语言编写的程序,他是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言
Shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务
3、Shell两大主流:
sh:
Bourne shell (sh),Solaris,hpux默认shell
Bourne again shell(bash),Linux系统默认shell
csh:
C shell(csh)
tc shell(tcsh)
4、#!声明
告诉系统其后路径所指定的程序即是解释此脚本的shell程序
#!/bin/bash
echo "Hello World !"
1.2 Shell脚本的执行
1、使用脚本的绝对路径或者相对路径
/root/helloworld.sh
./helloworld.sh
注意:文件必须为可执行文件
设置文件为可执行文件
chmod ug+x helloworld.sh
+替换成-号就是取消文件的x权限
2、bash或者sh+脚本
sh helloWorld.sh
当脚本没有x权限时,root和文件所有者通过该方式可以正常执行
3、在脚本的路径前再加"."或source
source helloWorld.sh
4、三者的区别
第一种和第二种:会新开一个进程来执行脚本文件,不同进程中的变量无法相互调用。
第三种:在当前进程里面执行脚本文件
5、export:可以将当前线程的变量传递给子进程去使用
变量引用的顺序:先从当前进程查询变量,如果当前进程没有这个变量,默认去父进程查询这个变量,依次类推
export修饰变量,是的这个变量对于子进程就是可见的
将来配置profile的时候,所有的变量前必须加export
二、shell基础入门
2.1shell变量
变量定义:
变量名不能加美元符号;
命名只能使用英文字母,数据和下划线,首个字符不能一数字开头;
中间不能有空格,可以使用下划线_;
不能使用标点符号;
不能使用bash里的关键字(可用help命令查看保留关键字)
变量类型:
-
局部变量
- 局部变量在脚本或者命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量
-
环境变量
- 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行
-
shell变量
- shell变量是由shell程序设置的特殊变量。shell变量中有一部分的环境变量,有一部分是局部变量
# 变量声明
name = 'zhangsan'
for file in `ls /etc`
或
for file in $(ls /etc)
#变量的调用
echo $name
echo ${name}
for skill in Ada Coffe Action Java; do
echo 'I am good at ${skill}Script'
done
#只读变量 /bin/sh: NAME: This variable is read only
url="http://www.google.com"
readonly url #设置url为只读变量,只读变量也不能删除
url="http://www.runoob.com"
#删除变量
unset name
2.2 Shell的字符串
- 字符串是shell编程中最常用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号
- 单引号
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字符串中不能出现单独一个的单引号,但可以成对出现,作为字符串拼接使用
- 双引号
- 双引号里可以有变量
- 双引号里可以出现转字符
#声明字符串
str1="helle world 1"
str2='hello world 2'
#字符串拼接--双引号
name='sunwukong'
name1="hello,"$name" !"
name2="hello,${name} !"
#字符串拼接--单引号
passwd='123456'
passwd1='hello,'$passwd' !'
passwd2='hello, ${passwd} !'
echo $passwd2 # hello,${passwd} !
# 字符串的长度
email="123456@qq.com"
echo ${#emali} # 获取字符串长度
echo ${email:1:4} # 获取字符串中下标从1到4的字符串(下标从0开始计数)
2.3 shell数组
- bash支持一维数组(不支持多维数组),并且没有限定数组的大小
- 数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以使整数或算数表达式,其 值应大于或等于0
# 定义数组 括号来表示数组,数组元素用”空格“符号分离开
数组名=(值1 值2 ... 值n)
favs=("足球" "篮球" "乒乓球" "保龄球")
#读取数组${数组名[下标]}
fav=${favs[2]}
# 使用@符号可以获取数组中所有的元素
echo ${favs[@]}
# 获取数组的长度
length=${#favs[@]}
length=${#favs[*]}
2.4 shell注释
- 以#开头的行就是注释,会被解释器忽略
- 通过每一行加一个#号设置多行注释
#--------------------
#这是一个注释
# auther
# site;
#--------------------
##### 服务器配置-start #####
#
#
#
#
#
##### 服务器配置-end #####
2.5 shell参数传递
- 执行shell脚本是,向脚本传递参数,脚本内获取参数的格式为:$n。n代表一个数字
参数处理 | 参数说明 |
---|---|
$# | 传递到脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 |
$0 | 执行的文件名 |
#!/bin/bash
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
# ./hello.sh 11 22 33 44
三、shell高级进阶
3.1 Shell运算符
所有的运算符跟变量之间记得有”空格“
- 算数运算符
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | expr $a + $b |
- | 减法 | expr $a - $b |
* | 乘法 | expr $a \* $b |
/ | 除法 | expr $a / $b |
% | 取余 | expr $a % $b |
= | 赋值 | a=$b |
== | 相等。用于比较两个数字,相同则返回true。 | [$a==$ b] |
!= | 不相等。用于比较两个数字,不行通则返回true。 | [$a!=$ b] |
- 关系运算符
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回true | [$a -eq $ b] |
-ne | 检测两个数是否不相等,不相等返回true | [$a -ne $ b] |
-gt | 检测左边的数是否大于右边的,如果是,则返回true | [$a -gt $ b] |
-lt | 检测左边的数是否小于右边的,如果是,则返回true | [$a -lt $ b] |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回true | [$a -ge $ b] |
-le | 检测左边的数是否小于等于右边的,如果是,则返回true | [$a -le $ b] |
- 布尔运算符
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为true则返回false,否则返回true | [! false] |
-o | 或运算,有一个表达式为true,则返回true | [$a -lt 20 -o $ b -gt 100] |
-a | 与运算,两个表达式都为true,才返回true | [$a -lt 20 -a $ b -gt 100] |
- 字符串运算符
运算符 | 说明 | 举例 | ||
---|---|---|---|---|
&& | 逻辑的AND | [[$a -lt 100 && $ b -gt 100]] | ||
|| | 逻辑的OR | [[`$a -lt 100 \ | \ | $`b -gt 100]] |
- 字符串运算符
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回true | [$a = $ b] |
!= | 检测两个字符串是否相等,不相等返回true | [$a != $ b] |
-z | 检测字符串长度是否为0,为0返回true | [-z $a] |
-n | 检测字符串长度是否不为0,不为0返回true | [-n $a] |
$ | 检测字符串是否为空,不为空返回true | [$a] |
- 文件检测运算符
运算符 | 说明 | 举例 |
---|---|---|
-r | 文件是否可读,可读返回true | [-r $file] |
-w | 文件是否可写,可写返回true | [-w $file] |
-x | 文件是否可执行,可执行返回true | [-d $file] |
-f | 文件是否为普通文件,普通文件返回true | [-f $file] |
-d | 文件是否为目录,为目录返回true | [-d $file] |
-s | 文件是否为空,不为空返回true | [-s $file] |
-e | 文件是否存在,存在返回true | [-e $file] |
3.1.1 算数运算符
#!/bin/bash
a=10
b=20
val=`expr $a + $b`
echo "a + b : ${val}"
echo `expr $a - $b`
echo `expr $a \* $b`
echo `expr $a / $b`
echo `expr $a % $b`
if [$a == $b]
then
echo "a等于b"
fi
if [$a != $b]
then
echo "a不等于b"
fi
3.1.2 关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
#!/bin/bash
a=10
b=20
if [$a -eq $b]
then
echo "a=b"
fi
if [$a -ne $b]
then
echo "a不等于b"
fi
if [$a -gt $b]
then
echo "a大于b"
fi
if [$a -lt $b]
then
echo "a小于b"
fi
if [$a -ge $b]
then
echo "a大于等于b"
fi
if [$a -le $b]
then
echo "a小于等于b"
fi
3.1.3 布尔运算符
a=10
b=20
if [$a != $b]
then
echo "a不等于b"
else
echo "a==b"
fi
if [$a -lt 100 -a $b -gt 15]
then
echo "true"
else
echo "false"
fi
if [$a -lt 100 -o $b -gt 100]
then
echo "true"
else
echo "flase"
if
3.1.4 逻辑运算符
#!/bin/bash
a=10
b=20
if [[$a -lt 100 && $b -gt 15]]
then
echo "true"
else
echo "flase"
fi
if [[$a -gt 100 || $b -gt 15]]
then
echo "true"
else
echo "false"
fi
3.1.5 字符串运算符
#!/bin/bash
a="abc"
b="efg"
if [$a = $b]
then
echo "a等于b"
else
echo "a不等于b"
fi
if [$a != $b]
then
echo "a不等于b"
else
echo "a等于b"
fi
if [-z $a]
then
echo "a长度为0"
else
echo "a长度不为0"
fi
if [-n $a]
then
echo "a长度不为0"
else
echo "a长度为0"
fi
if [$a]
then
echo "a为空"
else
echo "a不为空"
fi
3.1.6 文件检测运算符
#!/bin/bash
file="/val/node/text.sh"
if [-r $file]
then
echo "文件是可读的"
else
echo "文件不可读"
fi
if [-w $file]
then
echo "文件是可写的"
else
echo "文件不可写"
fi
if [-x $file]
then
echo "文件是可执行文件"
else
echo "文件不可执行"
fi
if [-f $file]
then
echo "文件是普通文件"
else
echo "文件不是普通文件"
fi
if [-d $file]
then
echo "文件是目录"
else
echo "文件不是目录"
fi
if [-s $file]
then
echo "文件不为空"
else
echo "文件为空"
fi
if [-e $file]
then
echo "文件存在"
else
echo "文件不存在"
fi
3.2 echo打印数据
- echo指令用于字符串输出
## 显示普通字符串
echo "Hello World"
## 显示转义字符
echo "\"Hello world\""
## 显示变量
name="zhangsan"
echo "${name}Hello World"
## 显示换行
echo -e "OK! \n"
echo "Hello World"
## 显示不换行
echo -e "OK! \c"
echo "Hello World"
## 显示结果定向至文件
echo "Hello World" > myfile # 该操作为覆盖操作,而非追加操作
## 原样输出字符串
echo '$name\"' ##使用单引号,不转义
## 显示命令执行结构
echo `date`
3.3 test命令
- shell中的test命令用于检测某个条件是否成立,他可以进行数值、字符和文件三个方面的测试
- 数字
参数 | 说明 |
---|---|
-eq | 等于则为真 |
-ne | 不等于则为真 |
-gt | 大于则为真 |
-lt | 小于则为真 |
-ge | 大于等于则为真 |
-le | 小于等于则为真 |
- 字符串
参数 | 说明 |
---|---|
= | 等于为真 |
!= | 不等于为真 |
-z 字符串 | 字符串长度为0则为真 |
-n 字符串 | 字符串长度不为0则为真 |
- 文件测试
参数 | 说明 |
---|---|
-e 文件名 | 文件存在则为真 |
-r 文件名 | 文件可读则为真 |
-w 文件名 | 文件可写则为真 |
-x 文件名 | 文件可执行则为真 |
-s 文件名 | 文件存在且至少有一个字符则为真 |
-d 文件名 | 文件存在且为目录则为真 |
-f 文件名 | 文件存在且为普通文件则为真 |
-c 文件名 | 文件存在且为字符型特殊文件则为真 |
-b 文件名 | 文件存在且为块特殊文件则为真 |
# 比较
num1=100
num2=200
if test $[num1] -eq $[num2]
then
echo "两个数字相等"
else
echo "不相等"
fi
3.4 shell流程控制
3.4.1 if
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
3.4.2 case
case 值 in
值1)
command1
;;
值2)
command2
;;
esac
例子
echo "输入1到4之间的数字"
echo "你输入的数字为"
read num
case ${num} in
1)
echo "你选择了1"
;;
2)
echo "你选择了2"
;;
3)
echo "你选择了3"
;;
4)
echo "你选择了4"
;;
*)
echo "你没有选择1到4之间的数字"
;;
esac
3.4.3 for
- 当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前值。
- 命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。
- in列表是可选的,如果不用它,for循环使用命令行的位置参数。
for var in item1 item2 item3 ... itemn
do
command1
command2
...
commandN
done
for loop in 1 2 3 4 5
do
echo "the value is : ${loop}"
done
for str in 'This is a string','hello moto'
do
echo ${str}
done
3.4.4 while循环
- while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件
while condition
do
command
done
# Bash let 命令,它用于执行一个或多个表达式,变量计算不需要加上$来表示变量
#!/bin/bash
i=1
while((${i}<=5))
do
echo ${i}
let "i++"
done
# 无限循环
while true
do
command
done
3.4.6 break
- 结束整个循环
#!/bin/bash
while true
do
echo -n "输入1到5之间的数字"
read num
case ${num} in
1|2|3|4|5) echo "您输入的数字 为${num}!"
;;
*) echo "你输入的数字不在1到5之间!游戏结束"
break
;;
esac
done
3.4.7 continue
- 跳出当次循环,继续下次循环
#!/bin/bash
while true
do
echo -n "输入1到5之间的数字"
read num
case ${num} in
1|2|3|4|5) echo "您输入的数字 为${num}!"
;;
*) echo "你输入的数字不在1到5之间!"
continue
;;
esac
done
3.5 函数
- linux shell 可以用户定义函数,然后再shell脚本中可以随意调用
- 可以带fuction fun()定义,也可以直接fun(),不带任何参数
- 参数返回,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值,return后跟数值n(0-255)
#!/bin/bash
## 第一个函数
demoFun(){
echo "这是第一个shell函数!"
}
echo "函数开始执行"
demoFun
echo "函数执行结束"
## 函数返回值
funWithReturn(){
echo "这个函数计算两个数的算数和"
read num1
read num2
return `expr ${num1} + ${num2}`
}
num = funWithReturn
# 函数返回值也可以在调用方法后通过$?来获得
echo "数字之和为$?"
# 函数传参
funWithParam(){
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "第三个参数为:$3"
echo "总共有$#个参数"
echo "作为一个字符串输出所有参数$*"
}
funWithParam 1 2 3
四、系统任务设置
4.1 系统启动流程
1、启动计算机的硬件
- 读取时间(每次电脑开机时间时间为什么都是对的)
- 选择对应的启动模式(是U盘启动,还是磁盘启动)
2、如果是Linux系统,回去找/boot目录.引导这个系统启动
3、计算机系统开始启动,读取初始化文件配置
-
vim /etc/inittab
-
启动时控制着计算机的运行级别runlevel
| 0 | halt(关机) |
| - | --------------------------------------------------- |
| 1 | Single user mode(单用户模式) |
| 2 | Multiuser,without NFS(多用户模式,但是无网络状态) FS->FileSystem |
| 3 | Full multiuser mode(多用户完整模式) |
| 4 | unused(保留模式) |
| 5 | X11(用户界面模式) |
| 6 | reboot(重启模式) |
Id:3\:inindefault:默认runlevel为3
- 以runlevel=3开始启动对应的服务和组件
4.2 系统服务
- 我们可以通过chkconfig命令查看当前虚拟机的服务
- 通过查看可以得知不同的级别对应到每一个服务确定本次开机自启动
- 开机结束后,我们需要使用service(Centos6)Systemmctl(Centos7)命令控制服务的开启或者关闭
4.3 开机自启动服务
以开机时修改时间脚本为例
方式一、rc.local
- 首先创建脚本存放的文件夹
- mkdir -p /user/local/scripts
- 在文件夹中创建脚本文件
- vim hello.sh
- 给与执行权限 chmod ug+x hello.sh
- 去/tec/rc.d/rc.local文件夹中添加脚本的绝对路径
- 给与rc.local执行权限 chmod ug+x rc.local
- 修改系统时间,是为了校验时间是否会在重启时被脚本执行修改
- date -s ‘21-21-21’
- 重启虚拟机
- reboot
方式二、chkconfig
-
创建开机自启动脚本文件
-
vim schoolnptdate.sh
```shell
#!/bin/bash
#chkconfig: 2345 88 99
#description:auto_run
# 设置自启动同步时间
yum info ntp && ntpdate cn.ntp.org.cn
```
chkconfig : 2345 88 99
**服务器启动,在脚本中必须要加**
2345表示的是runlevel为2,3,4,5时启动该脚本
88表示start的顺序
99表示kill的顺序
-
给其设置执行权限
- chmod u+x schoolntpdate.sh
-
将脚本拷贝到/tec/init.d目录下
- cp schoolntpdate.sh /etc/init.d/
-
添加到服务
- chkconfig --add /etc/init.d/schoolntpdate.sh
-
修改系统时间,是为了校验时间是否会在重启时被脚本执行修改
- date -s ‘21-21-21’
-
重启服务器
- reboot
4.4 定时任务
-
在系统服务中心,crond负责周期任务
- systemctl status crond.service
-
添加任务,编辑当前用户的任务列表
- crontab -e
-
编辑任务
-
重启crontab,使配置生效
- systemctl restart crond.service
-
查看当前定时任务
- crontab -l
-
查看任务的历史
- vim /var/spool/mail/root
-
清除任务
- crontab -r