Shell基础入门
一、什么是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"
unset A
echo "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 $A
echo ""
NOW_DATE=$(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 "$0 $1 $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就可以了
- 解决办法:去掉 -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