Shell基础入门

Lou.Chen
大约 11 分钟

一、什么是Shell

Shell 是一个命令行解释器,它为用户提供了一个向 Linux 内核发送请求以便运行程序的界面系统级程序,用户可以用 Shell 来启动、挂起、停止甚至是编写一些程序.

二、Shell脚本的执行方式

1、脚本格式要求

  • 脚本以 #!/bin/bash 开头
  • 脚本需要有可执行权限

例如

1)新建helloworld.sh 文件,并加入内容

#!/bin/bash
echo "hello world!"  #在控制台输出 helloworld

2、脚本的常用执行方式

1)输入脚本的绝对或相对路径

  • 首先要赋予 helloworld.shopen in new window 脚本的 +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、将命令的返回值赋给变量

  1. A=`ls -l /opt` 反引号,运行里面的命令,并把结果返回给变量
  • 将opt目录下的内容赋值给变量A
  1. 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 "备份文件成功"

  • 注意
    • 问题:因为我们mysqldocker中,所以使用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