shell编程
shell 是一个命令行解释器,他为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell 来启动、挂起、停止甚至是编写一些程序
shell 脚本的执行方式
脚本格式要求:
- 脚本以#!/bin/bash开头
- 脚本需要有可执行权限
[ylq@rootylq shell]$ cat hello.sh
#!/bin/bash
echo "hello,world"
以脚本的绝对路径或相对路径执行shell
[ylq@rootylq shell]$ vim hello.sh
[ylq@rootylq shell]$ ./hello.sh
-bash: ./hello.sh: Permission denied
[ylq@rootylq shell]$ ll
total 4
-rw-rw-r-- 1 ylq ylq 31 Jan 18 10:59 hello.sh
[ylq@rootylq shell]$ chmod u+x hello.sh
[ylq@rootylq shell]$ ./hello.sh
hello,world
用sh+脚本执行
[ylq@rootylq shell]$ sh hello.sh
hello,world
shell的变量
- Linux Shell 中的变量分为,系统变量和用户自定义变量
系统变量
$HOME, $PWD ,$SHELL, $USER等
[ylq@rootylq shell]$ echo $HOME
/home/ylq
[ylq@rootylq shell]$ echo $home
[ylq@rootylq shell]$ echo $PWD
/home/ylq/shell
[ylq@rootylq shell]$ echo $USER
ylq
- 可通过set指令查看所有的系统变量
[ylq@rootylq shell]$ set |more
自定义变量
定义变量
变量名=值
撤销变量
unset 变量
声明静态变量
readonly 变量,注意不能unset
#!/bin/bash
#定义变量
A=100
#输出变量需要加上$
echo A=$A
echo "A=$A"
#撤销变量A
unset A
echo A=$A
#声明静态变量,不能unset
readonly B=2
echo "B=$B"
unset B
[ylq@rootylq shell]$ ./var.sh
A=100
A=100
A=
B=2
./var.sh: line 16: unset: B: cannot unset: readonly variable
shell 变量命名规范
- 变量名称可以由字母、数字和下划线组成,但不能以数字作为开头
- 等号两侧不能由空格
- 变量名称一般习惯为大写
将命令的返回值赋给变量
A=`date`
A=$(date)
C=`date`
echo C=$C
D=$(date)
echo D=$D
[ylq@rootylq shell]$ ./var.sh
A=100
A=100
A=
B=2
C=Wed Jan 18 11:26:38 CST 2023
D=Wed Jan 18 11:26:38 CST 2023
设置环境变量
基本语法
- export 变量名=变量值 (功能描述:将shell变量输出为环境变量/全局变量)
- source 配置文件 (功能描述:让修改后的配置信息立即生效)
- echo $变量名 (功能描述:查询环境变量的值)
设置环境变量,可以使得多个函数共享变量
#定义一个环境变量
export YLQPATH=/home/ylq
[root@rootylq ~]# vim /etc/profile
[root@rootylq ~]# exco $YLQPATH
-bash: exco: command not found
[root@rootylq ~]# echo $YLQPATH
[root@rootylq ~]# source /etc/profile
[root@rootylq ~]# echo $YLQPATH
/home/ylq
shell 脚本的多行注释
:<<!
注释内容
!
位置参数变量
当执行一个shell脚本时,如果希望获取到命令行的参数信息,就可以使用到位置参数变量
基本语法
- $n
n代表数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数需要用大括号表示,如${10}
- $* 这个变量代表命令行中的所有参数,把所有的参数看成一个整体
- $@ 代表命令行中所有的参数,但把每个参数区分对待
- $# 代表命令行中所有参数的个数
#!/bin/bash
echo "$0 1=$! 2= $2"
echo "所有参数=$*"
echo “$@”
echo "参数个数=$#"
[root@rootylq shell]# chmod u+x myshell.sh
[root@rootylq shell]# ./myshell.sh 100 200
./myshell.sh 1= 2= 200
所有参数=100 200
“100 200”
参数个数=2
[root@rootylq shell]#
预定义变量
就是shell 设计者事先已经定义好的变量,可以直接在shell 脚本中使用
基本语法:
- $$ 当前进程的进程号
- $! 后台运行的最后一个进程的进程好
- $? 最后一次执行的命令返回状态,如果这个变量的值为0。证明上一个命令正确;如果这个变量的值非0,则证明上一个命令执行不正确
#!/bin/bash
echo "当前执行的进程id=$$"
#以后台方式运行一个脚本,并获取他的进程号
/home/ylq/shell/myshell.sh &
echo "最后一个后台方式运行的子进程i=$!"
echo “执行结果是=$?”
[root@rootylq shell]# chmod u+x preVAr.sh
[root@rootylq shell]# ./pre
-bash: ./pre: No such file or directory
[root@rootylq shell]# ./preVAr.sh
当前执行的进程id=18024
最后一个后台方式运行的子进程i=18025
“执行结果是=0”
[root@rootylq shell]# /home/ylq/shell/myshell.sh 1= 2=
所有参数=
“”
参数个数=0
^C
shell 运算符
如何在shell中使用各自运算操作符
基本语法
$((运算式))或$[运算式]或expr m + n
- expr 运算符之间要有空格,如果需要将expr的结果赋给某个变量,使用``
- expr m - n
expr \*,/,% 乘,除,取余
[root@rootylq shell]# ./oper.sh 30 40
RES1=20
RES2=20
RES3=20
SUM=70
[root@rootylq shell]# cat oper.sh
#!/bin/bash
#计算(2+3)*4 的值
#使用第一种方法
RES1=$(((2+3)*4))
echo "RES1=$RES1"
#使用第二种方式
RES2=$[(2+3)*4]
echo "RES2=$RES2"
#使用第三种方式 expr
TEMP=`expr 2 + 3`
RES3=`expr $TEMP \* 4`
echo "RES3=$RES3"
SUM=$[$1+$2]
echo "SUM=$SUM"
shell 条件判断
基本语法
[ condition ] 注意condition 前后都需要有空客
#非空返回true ,可使用$? 验证(0为true,>1为false)
判断语句
- = 字符串比较
- 两个整数的比较
- -lt 小于
- -le 小于等于 little equal
- -eq 等于
- -gt 大于等于
- -ne 不等于
- 按照文件权限进行判断
- -r 有读权限
- -w 有写权限
- -x 有执行权限
- 按照文件类型进行判断
- -f 文件存在并且是一个常规的文件
- -e 文件存在
- -d 文件存在并是一个目录
[root@rootylq shell]# ./ifdemo.sh
equal
23大于22
文件存在
[root@rootylq shell]# cat ifdemo.sh
#!/bin/bash
#判断字符串是否相同
if [ "ok" = "ok" ]
then
echo "equal"
fi
#判断23是否发育22
if [ 23 -ge 22 ]
then
echo "23大于22"
fi
#判断文件目录中文件是否存在
if [ -f /home/ylq/shell/myshell.sh ]
then
echo "文件存在"
fi
if [ ]
then
echo "看我存在不"
fi
shell 流程控制
if 单分支与多分支
单分支
if [ ]
then
echo "看我存在不"
fi
多分支
[root@rootylq shell]# chmod u+x ifcase.sh
[root@rootylq shell]# ./ifcase.sh 70
及格了,哥们
[root@rootylq shell]# ./ifcase.sh 59
不及格,回家有你好果子吃
[root@rootylq shell]# cat ifcase.sh
#!/bin/bash
if [ $1 -ge 60 ]
then
echo "及格了,哥们"
elif [ $1 -lt 60 ]
then
echo "不及格,回家有你好果子吃"
fi
[ 条件判断式 ],中括号和条件判断式之间必须要有空格
case 语句
case $变量名 in
“值1”)
程序1
;;
“值2”
程序2
;;
…
esac
[root@rootylq shell]# chmod u+x casedemo.sh
[root@rootylq shell]# ./casedemo.sh 1
Monday
[root@rootylq shell]# ./casedemo.sh 2
Tuesday
[root@rootylq shell]# ./casedemo.sh 3
Wednesay
[root@rootylq shell]# ./casedemo.sh 4
Other...
[root@rootylq shell]# cat casedemo.sh
#!/bin/bash
case $1 in
"1")
echo "Monday"
;;
"2")
echo "Tuesday"
;;
"3")
echo "Wednesay"
;;
*)
echo "Other..."
;;
esac
for循环
基本语法1:
for 变量 in 值1 值2 …
do
程序
done
基本语法2
for ((初始值;循环控制条件;变量变化))
do
程序
done
[root@rootylq shell]# ./fordemo.sh 100 200 300
测试*
num is 100 200 300
*******************************
测试@
num@ is 100
num@ is 200
num@ is 300
./fordemo.sh: line 21: echo*********************************************: command not found
测试基本语法,打印1~10
SUM=1
SUM=3
SUM=6
SUM=10
SUM=15
SUM=21
SUM=28
SUM=36
SUM=45
SUM=55
[root@rootylq shell]# cat fordemo.sh
#!/bin/bash
#$*将输入的参数当作一个整体,所以只会输出一句话
echo "测试*"
for i in "$*"
do
echo "num is $i"
done
#$@ 将输入的参数分别对待,有几个参数九江输出几句话
echo "*******************************"
echo "测试@"
for i in "$@"
do
echo "num@ is $i"
done
echo"*********************************************"
echo "测试基本语法,打印1~10"
SUM=0
for(( i=1; i<=10; i++))
do
SUM=$[ $SUM+$i ]
echo "SUM=$SUM"
done
while 循环
while [ 条件判断式 ]
do
程序
done
[root@rootylq shell]# ./whiledemo.sh 100
执行结果=5050
[root@rootylq shell]# ./whiledemo.sh 10
执行结果=55
[root@rootylq shell]# cat whiledemo.sh
#!/bin/bash
SUM=0
i=0
while [ $i -le $1 ]
do
SUM=$[ $SUM+$i ]
#i自增
i=$[ $i+1 ]
done
echo "执行结果=$SUM"
read 读取控制台输入
read(选项)(参数)
选项:
-
-p: 指定读取值时的提示符
-
-t: 指定读取值时的等待时间(秒),如果没有在指定的时间内输入,就不再等待了
参数:
- 指定读取值的变量名
[root@rootylq shell]# vim readdemo.sh
[root@rootylq shell]# ./readdemo.sh
请输入一个数NUM1=10
输入的值是:10
请在10秒内输入一个数NUM2= 20
输入的值是NUM2=20
[root@rootylq shell]# ./readdemo.sh
请输入一个数NUM1=10
输入的值是:10
请在10秒内输入一个数NUM2= 输入的值是NUM2=
[root@rootylq shell]# cat readdemo.sh
#!/bin/bash
read -p "请输入一个数NUM1=" NUM1
echo "输入的值是:$NUM1"
read -t 10 -p "请在10秒内输入一个数NUM2= " NUM2
echo "输入的值是NUM2=$NUM2"
函数
shell函数可以有自定义函数,也可以有系统函数
系统函数
basename
返回完整路径/后的部分,常用于获取文件名
basename[ pathname ] [ suffix ]
basename 命令会删掉所有的后缀包括最后一个/字符,将字符串显示出来
suffix为后缀,如果suffix被制定了,basename会将pathname或string 的suffix去掉
[root@rootylq shell]# clear
[root@rootylq shell]# basename /home/ylq/shell/myshell.sh
myshell.sh
[root@rootylq shell]# basename /home/ylq/shell/myshell.sh .txt
myshell.sh
[root@rootylq shell]#
dirname
功能:返回完整路径最后/的前面部分,常用于返回路径部分
dirname 文件绝对路径
功能描述:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录部分)
[root@rootylq shell]# dirname /home/ylq/shell/myshell.sh
/home/ylq/shell
[root@rootylq shell]#
自定义函数
[ function ] funname [()]
{
Action;
[return int;]
}
调用直接写函数名: funname [值]
[root@rootylq shell]# ./functiondemo.sh
请输入n1=10
情输入n2=20
SUM is 30
[root@rootylq shell]# cat functiondemo.sh
#!/bin/bash
#定义函数 getSum
function getSum(){
SUM=$[ $n1+$n2 ]
echo "SUM is $SUM"
}
#输入两个值
read -p "请输入n1=" n1
read -p "情输入n2=" n2
#调用自定义函数
getSum $n1 $n2
shell 编程综合案例
备份数据库:
- 每天凌晨2:30备份数据库
- 备份开始和结束能够给出提示
- 备份文件要求以备份时间为文件名,并打包成.tar.gz形式
- 备份同时检查,是否有10天前的备份数据库文件,如果存在则删除
[root@rootylq ~]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
[root@rootylq ~]# crontab -l
30 2 * * * /usr/sbin/mysql_db_backup.sh
#!/bin/bash
#备份目录
BACKUP=/data/backup/db
#获取当前时间
DATETIME=$(date +%Y-%m-%d_%H%M%S)
echo $DATETIME
#数据库地址
HOST=localhost
#数据库用户名
DB_USER=root
DB_PW=Ylq1368670840!
#要备份的数据库
DATABASE=aliyun
#创建备份目录,如果不存在则创建
[ ! -d "${BACKUP}/${DATETIME}" ] && mkdir -p "${BACKUP}/${DATETIME}"
#开始备份数据库
mysqldump -u${DB_USER} -p${DB_PW} --host=${HOST} -q -R --databases ${DATABASE} |gzip > ${BACKUP}/${DATETIME}/$DATETIME.sql.gz
#将文件处理成tar.gz
cd ${BACKUP}
tar -zcvf $DATETIME.tar.gz ${DATETIME}
#删除对应的备份目录
rm -rf ${BACKUP}/${DATETIME}
#删除10天前的备份
find ${BACKUP} -atime +10 -name "*.tar.gz" -exec rm -rf {} \;
echo "备份数据库${DATABASE}成功-"