一、什么是Shell
Shell 是一个命令行解释器,它为用户提供了一个向 Linux 内核发送请求以便运行程序的界面系统级程序,用户可以用 Shell 来启动、挂起、停止甚至是编写一些程序.
#二、Shell脚本的执行方式
#1、脚本格式要求
脚本以 #!/bin/bash 开头
脚本需要有可执行权限
例如
1)新建helloworld.sh 文件,并加入内容
#!/bin/bash
echo "hello world!" #在控制台输出 helloworld
#2、脚本的常用执行方式
1)输入脚本的绝对或相对路径
首先要赋予 helloworld.sh 脚本的 +x 权限
修改文件权限为可执行,本组其他用户可执行,其他组用户可执行
chmod 755 helloworld.sh
执行脚本
绝对路径
/root/myshell/helloworld.sh
相对路径
./helloworld.sh
2)sh+脚本(不推荐)
可以不必事先设定shell的执行权限,甚至都不用写shell文件中的第一行(指定bash路径)。因为是将helloworld.sh作为参数传给sh(bash)命令来执行的。这时不是helloworld.sh自己来执行,而是被调用执行,所以可以不要执行权限。
可以不赋予权限
sh helloworld.sh
#或者
bash helloworld.sh
#三、Shell变量
#1、简介
Linux Shell 中的变量分为,系统变量和用户自定义变量
系统变量
HOME、PWD、SHELL、USER 等
定义变量:变量=值
#!/bin/bash
echo "path=PATH"echo"user=USER"
set 显示所有shell变量
#2、变量的定义
定义变量:变量名=值
引用变量:
变量名
∗
∗
或
∗
∗
变量名∗∗或∗∗{变量名}
撤销变量:unset 变量名
声明静态变量(只读):readonly 变量名=值,注意:不能 unset
例1:
定义变量 A=100
撤销变量 A
#!/bin/bash
A=100
echo "A=A"unsetAecho"A=A"
例2:
定义一个静态变量,不可unset
#!/bin/bash
readonly A=100
echo "A=$A"
unset A
#3、定义变量的规则
变量名称可以由字母、数字和下划线组成,但是不能以数字开头
等号两侧不能有空格
变量名称一般习惯为大写
#4、将命令的返回值赋给变量
A=ls -l /opt 反引号,运行里面的命令,并把结果返回给变量
将opt目录下的内容赋值给变量A
NOW_DATE=$(date) 等价于反引号
将date指令输出的日期赋值给NOW_DATE变量
#!/bin/bash
A=ls /opt
echo Aecho""NOWDATE=(date)
echo $NOW_DATE
#四、设置系统环境变量
基本语法
export 变量名=变量值 (功能描述:将 shell 变量输出为环境变量)
source 配置文件路径 (功能描述:让修改后的配置信息立即生效)
echo $变量名 (功能描述:输出环境变量的值到控制台)
Shell中多行的注释:
:<<!
注释内容
注释内容
!
例如
1)在 /etc/profile文件中为TOMCAT_HOME添加环境变量
TOMCAT_HOME=/opt/tomcat_7.0
export TOMCAT_HOME
2)让修改的配置文件立即生效
source /etc/profile
3)控制台查看环境变量 TOMCAT_HOME 的值
echo $TOMCAT_HOME
4)在helloworld.sh文件中使用环境变量
#!/bin/bash
:<<!
这是注释的内容
哈哈哈
!
#使用自定义的环境变量
echo "tomcathome=$TOMCAT_HOME"
执行helloword.sh脚本
#五、位置参数变量
当我们执行一个 shell 脚本时,如果希望获取到命令行的参数信息,就可以使用到位置参数变量,比如 : ./myshell.sh 100 200 , 这个就是一个执行 shell 的命令行,可以在 myshell 脚本中获取到参数信息
基本语法
$n
功能描述:n 为数字,0代表命令本身,1-9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如
$*
功能描述:这个变量代表命令行中所有的参数,∗把所有的参数看成一个整体@
功能描述:这个变量也代表命令行中所有的参数,不过@把每个参数区分对待#
功能描述:这个变量代表命令行中所有参数的个数
例如
1)新建positionPara.sh脚本文件,加入以下内容
#!/bin/bash
#获取命令的各个参数
echo "01 2"echo"*"
echo "@"echo"#"
2)执行脚本并传入参数 ./positionPara.sh 100 200 300
#六、预定义变量
就是 shell 设计者事先已经定义好的变量,可以直接在 shell 脚本中使用
当前进程的进程号(PID)
$!
后台运行的最后一个进程的进程号(PID)
$?
最后一次执行的命令的返回状态。如果这个变量的值为 0,证明上一个命令正确执行;如果这个变量的值为非 0(具体是哪个数,由命令自己来决定),则证明上一个命令不正确
例如
1)新建 preVar.sh脚本文件,加入以下内容
#!/bin/bash
echo "当前的进程号:$$"
#后台运行helloworld.sh脚本
./hellowrold.sh &
echo "最后执行的进程号:$!"
echo "最后一次执行的命令的返回状态:$?"
2)执行该脚本 ./preVar.sh
#七、运算符
如何在 shell 中进行各种运算操
以下几种操作均可以
① “$((运算式))”
② “$[运算式]” (常用)
③ `expr m + n** 或 **\expr m - n` (符合:+, -, \*, /, %) ,乘号 * 要用 \ 转义
注意 expr 运算符要有空格
例1:
计算(2+3)*4的值
新建caculate.sh脚本文件,测试以下内容
①“$((运算式))"
RESULT_1="$(((2+3)*4))"
echo RESULT_1=$RESULT_1
②“$[运算式]" (常用)
RESULT_2="$[(2+3)*4]"
echo RESULT_2=$RESULT_2
③`expr m + n`
TEMP=`expr 2 + 3`
RESULT_3=`expr $TEMP \* 4`
echo RESULT_3=$RESULT_3
例2:
计算命令行执行输入参数的和 ./caculate.sh 100 200
#!/bin/bash
RESULT_4="$[$1+$2]"
echo RESULT_4=$RESULT_4
输出结果
#八、判断语句
#1、基本语法
[ condition ]
注意 condition 前后要有空格
非空返回 true,可使用$?验证(0 为 true,>1 为 false)
例如:
[ louchen ] 返回true
[] 返回false
[ condition ] && echo "ok" || echo "notok"
[ condition ]为真, 输出 "ok"
[] && echo "ok" || echo "notok"
[] 为假,输出 "notok"
#2、常用条件判断
#1)字符串和整数的比较
以下为字符串比较:
= 字符串比较 [ "字符串1" = "字符串2" ]
注意:等号两边需要加空格
以下为整数比较:
-lt 小于 [ 整数1 -lt 整数2]
-le 小于等于
-eq 等于
-gt 大于
-ge 大于等于
-ne 不等于
#2)按照文件权限进行判断
-r 有读的权限 [ -r 文件路径 ]
-w 有写的权限
-x 有执行的权限
#3)按照文件类型进行判断
-f 文件存在并且是一个常规的文件 [ -f 文件路径 ]
-e 文件是否存在
-d 文件存在并是一个目录
#3)实例
①"ok"是否等于"ok"
#!/bin/bash
if [ "ok" = "ok" ]
then
echo "等于"
fi
其中 fi 代表**finsh **判断结束
② 23 是否大于等于 22
#!/bin/bash
if [ 23 -ge 22 ]
then
echo "大于或等于"
fi
③判断 /root/hello.log 目录中的文件是否存在
在/root/myshell/ 文件夹下新建 hello.log 文件
#!/bin/bash
if [ -e /root/myshell/hello.log ]
then
echo "文件存在"
fi
#九、流程控制
#1、if判断
第一种方式
if [ 条件判断式 ];then
程序
fi
第二种方式(常用)
if [ 条件判断式 ]
then
程序
elif [条件判断式]
then
程序
fi
注意:
[ 条件判断式 ],中括号和条件判断式之间必须有空格
例如:
编写一个 shell脚本,如果输入的参数,大于等于 60,则输出 "及格了",如果小于 60,则输出 "不及格"
#!/bin/bash
if [ $1 -ge 60 ]
then
echo "及格了"
elif [ $1 -lt 60 ]
then
echo "不及格"
fi
#2、case语句
基本语法
case $变量名 in
"值1")
如果变量的值等于值 1,则执行程序 1
;;
"值2")
如果变量的值等于值 2,则执行程序 2
;;
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
例如:
当命令行参数是 1 时,输出 "周一", 是 2 时,就输出"周二",是3时,就输出"周三",其它情况输出 "other"
#!/bin/bash
case $1 in
"1")
echo "周一"
;;
"2")
echo "周二"
;;
"3")
echo "周三"
;;
*)
echo "其他"
;;
esac
#3、for循环
#1、基本语法1
for 变 量 in 值1 值2 值3
do
程序
done
*$ ,$@**的区别
$* 代表命令行中所有的参数,$*把所有的参数看成一个整体
$@ 代表命令行中所有的参数,不过$@把每个参数区分对待
例如:
题目:打印命令行输入的参数
①使用到$*
#!/bin/bash
for i in "$*"
do
echo "the num is $i"
done
遍历$*中的参数给i,这里$*将参数当做一个整体给i
②使用$@
#!/bin/bash
for i in "$@"
do
echo "the num is $i"
done
遍历$@中的参数给i,把每个输入的参数区别对待
#2、基本语法2
for((初始值;循环控制条件;变量变化))
do
程序
done
例如:
题目:从 1 加到 100 的值输出显示
#!/bin/bash
SUM=0
for((i=0;i<=100;i++))
do
SUM="$[$SUM+$i]"
done
echo SUM=$SUM
#4、while循环
基本语法
while [ 条件判断式 ]
do
程序
done
例子:
题目:从命令行输入一个数 n,统计从 1+...+ n 的值是多少?
新建 whilejudge.sh脚本文件,加入以下内容
#!/bin/bash
SUM=0
i=0
while [ $i -le $1 ]
do
SUM=$[$SUM+$i]
i=$[$i+1]
done
echo "SUM=$SUM"
#十、read 读取控制台输入
1、基本语法
read [选项] [选项值] [变量]
[选项]
-p 指定读取值时的提示符(prompt)
-t 指定读取值时等待的时间(秒),如果没有在指定的时间内输入,就不再等待了
[变量]
指定赋值的变量名
例子:
读取控制台输入一个 num1 值
读取控制台输入一个 num2 值,在 10 秒内输入。
新建 readtest.sh 脚本文件,并加入以下内容
#!/bin/bash
read -p "请输入num1的值:" NUM1
echo "您输入的num1=$NUM1"
read -p "等待时间为10s,请输入num2的值:" -t 10 NUM2
echo "您输入的num2=$NUM2"
#十一、函数
#1、系统函数
basename [文件路径]
返回完整路径最后 / 的部分,常用于获取文件名,包含后缀
basename [文件路径] [后缀]
返回完整路径最后 / 的部分,常用于获取文件名,不包含后缀
dirname [文件路径]
返回指定路径的文件目录路径,不包含最后的文件名和后缀
#2、自定义函数
基本语法
function 方法名(){
}
例如:
题目:定义一个方法,输入两个参数累加求和
新建 definefun.sh 脚本
#!/bin/bash
function add(){
SUM=$[$n1+$n2]
echo "n1+n2=$SUM"
}
read -p "请输入n1的值:" n1
read -p "请输入n2的值:" n2
#调用方法
add $n1 $n2
*/2 * * * * /root/vhr/mysql_db_backup.sh
#十二、常用案例
#1、MySQL定时备份
1)在/root/vhr/mysql_db_backup.sh脚本文件
#!/bin/bash
#备份的路径
BACKUP=/root/vhr/bak/db
#当前时间作为文件名
DATETIME=$(date +%Y_%m_%d_%H%M%S)
#echo $DATETIME
echo "======开始备份======"
echo "备份的路径是:$BACKUP/$DATETIME.sql"
#主机
HOST=localhost
#用户名
DB_USER=root
#密码
DB_PWD=xxxxxx
#备份的数据库名称
DATABASE=vhr
#如果备份的路径文件夹存在,就使用,否则创建
[ ! -d "$BACKUP" ] && mkdir -p "$BACKUP"
#执行mysql的备份数据库的指令,这里我们使用docker中的mysql
docker exec mysql01 mysqldump -u${DB_USER} -p${DB_PWD} --host=${HOST} $DATABASE > $BACKUP/$DATETIME.sql
#这里我们一天一次备份,只保留十天的备份文件
find $BACKUP -mtime +10 -name "*.sql" -exec rm -rf {} \;
echo "备份文件成功"
注意
问题:因为我们mysql在docker中,所以使用crontab定时执行的时候,如果在备份脚本中写 docker exec -it mysql01 ,那么备份的文件会mysqldump出来的文件大小始终是0
解决办法:去掉 -it ,即 docker exec mysql01 crontab定时执行的时候dump出来的文件大小始终是0,后来发现去掉-it就可以了
2)编写定时任务
执行 crontab -e 编写定时任务,加入以下内容
30 2 * * * /root/vhr/mysql_db_backup.sh >> /root/vhr/backup.txt
每天 2:30 执行 mysql_db_backup.sh 脚本文件完成数据库备份,并将脚本的执行日志追加到 /root/vhr/ 目录下的backup.txt文件中
crontab -l 查看所有定时任务
crontab -r 删除当前用户所有的crontab任务
systemctl restart crond 重启任务调度器
#2、重新启动Jar包
#!/bin/bash
APP_NAME=/opt/motiblog/moti-blog-0.0.1-SNAPSHOT.jar
LOG_FILE=/opt/motiblog/moti.log
pid=`ps -ef|grep $APP_NAME | grep -v grep | awk '{print $2}'`
kill -9 $pid
echo "$pid进程终止成功"
sleep 2
if test -e $APP_NAME
then
echo '文件存在,开始启动此程序...'
nohup java -jar $APP_NAME > $LOG_FILE 2>&1 &
echo "$APP_NAME 启动成功..."
else
echo "$APP_NAME 文件不存在,请检查"
fi