Skip to content

Linux Shell 编程

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

脚本执行方式

格式要求

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

Hello world!

#!/bin/bash
echo "Hello world!";

常用执行方式

  1. 首先赋予可执行权限,然后直接输入路径执行
  2. 无需赋予可执行权限,sh 脚本路径 执行

Shell 的变量

变量介绍

Linux Shell 的变量分为两种,系统变量和用户自定义变量
系统变量:$HOME $PWD $SHELL $USER
显示当前 Shell 的所有变量:set

变量定义

基本语法

  1. 定义变量:变量名=值 (中间不能有空格)
  2. 撤销变量:unset 变量名
  3. 声明静态变量:readonly 变量 (不能被销毁)
    #!/bin/bash
    A=100
    echo A=$A # 输出变量需要$
    unset A
    
    readonly B=200 # 不能更改,不能 unset
    echo B=$B
    

命名规则

  • 由字母、数字、下划线组成,不能以数字开头
  • 等号两侧不能有空格
  • 变量名称习惯大写

将命令的返回值赋给变量

  • A=`date` 使用反引号,运行里面的命令,并把结果返回给变量 A
  • A=$(date) 等价于反引号
    C=`date`
    D=$(date)
    echo C=$C
    echo D=$D
    

设置环境变量

export 变量名=变量值 将 Shell 变量输出为环境变量
source 配置文件 让修改后的配置信息立刻生效
echo $变量名 查询环境变量的值

多行注释

:<<! 开始,以 ! 结束,起止符全部独立一行

位置参数变量

在执行 Shell 脚本时,如果希望获得命令行的参数信息,就可以使用位置参数变量,例如 ./myshell.sh 100 200

基本语法

$n 其中 n 为数字,$0 代表命令本身,$1-9 代表第一到九个参数,十以上的参数需要大括号包含,如 ${10}
$* 代表命令行中所有参数,它把所有参数看成一个整体
$@ 代表命令行中所有参数,不过把每个参数区分对待
$# 代表命令行所有参数的个数

#!/bin/bash
echo "$0 $1 $2"
echo "所有参数* $*"
echo "所有参数@ $@"
echo "参数个数 $#"

预定义变量

$$ 当前进程号
$! 后台运行最后一个进程的进程号
$? 最后一次执行命令的返回状态,如果为 0 ,则说明正确执行,如果非 0 ,则未正确执行

echo "当前进程号 $$"
/root/shell/myshell.sh &
echo "后台运行最后一个进程号 $!"
echo "最后一次执行命令返回状态 $?"

Shell 运算符

基本语法

$((运算式))$[运算式]expr m + n
注意 expr 运算符中间有空格,如果要把 expr 结果赋给某个变量,需要使用 `expr m + n` 反引号,expr 中的运算符还有 \* / %

#!/bin/bash

RES1=$(((2+3)*4))
echo res1=$RES1

RES2=$[(2+3)*4]
echo res2=$RES2

TEMP=`expr 2 + 3`
RES3=`expr $TEMP \* 4`
echo res3=$RES3

Shell 判断语句

基本语法

[ condition ]
注意 condition 前后有空格,非空返回 true ,可使用 $? 验证( 0true>1false
[ condition ] && echo TRUE || echo FALSE 条件满足打印 TRUE 不满足打印 FALSE

常用判断条件

  1. = 字符串比较
  2. 两个整数比较
    • -lt 小于
    • -le 小于等于
    • -eq 等于
    • -gt 大于
    • -ge 大于等于
    • -ne 不等于
  3. 按照文件权限判断
    • -r 有读权限
    • -w 有写权限
    • -x 有执行权限
  4. 按照文件类型判断
    • -f 文件存在并是常规的文件
    • -e 文件存在
    • -d 文件存在并是一个目录
      #!/bin/bash
      if [ "ok" = "ok" ]
      then
              echo "equal"
      fi
      
      if [ 23 -ge 22 ]
      then
              echo "greater or equal"
      fi
      
      if [ -f /root/shell/aaa.txt ]
      then
              echo "file exist"
      else
              echo "file NOT exist"
      fi
      

Shell流程控制

if 语句

if [ 条件判断式 ]
then
    代码
fi

if [ 条件判断式 ]
then
    代码
elif [ 条件判断式 ]
then
    代码
fi

case 语句

case $变量名 in
"值1")
如果变量值等于值1,则执行语句1
;;
"值2")
如果变量值等于值2,则执行语句2
;;
*)
如果变量值不是以上的值,则执行该语句
;;
esac
#!/bin/bash
case $1 in
"1")
echo "Monday"
;;
"2")
echo "Tuesday"
;;
*)
echo "other"
;;
esac

for 语句

for 变量 in 值1 值2 值3...
do
循环代码
done

$*$@ 不加双引号是相同的,加双引号后 $* 总体加双引号, $@ 给每个分开的参数分别加双引号

#!/bin/bash
for i in "$*"
do
        echo "num is $i"
done

for i in "$@"
do
        echo "num is $i"
done

for((初始值;循环控制条件;变量变化))
do
循环代码
done
#!/bin/bash
SUM=0
for (( i=1; i<=100; i++ ))
do
    SUM=$[$SUM+$i]
done
echo SUM=$SUM

while 语句

while [ 条件判断式 ]
do
循环代码
done
注意 while[ 有空格,[] 内也有空格
#!/bin/bash
SUM=0
i=1
while [ $i -le $1 ]
do
    SUM=$[$SUM+$i]
    i=$[$i+1]
done
echo SUM=$SUM

Shell 系统函数

read 读取控制台输入

read [选项] 变量名
选项:
-p 指定读取值时的提示符
-t 指定读取值时等待的时间,如果没有在指定时间内输入就不再等待

#!/bin/bash
read -p "输入NUM1: " NUM1
echo NUM1=$NUM1

read -p "输入NUM2(10s): " -t 10  NUM2
echo NUM2=$NUM2

basename 返回文件名

basename [pathname] [suffix] 返回完整路径最后 / 的部分,常用于获取文件名
basename [string] [suffix] 删除所有的前缀包括最后一个 / 字符,然后显示字符串
其中,[suffix] 为后缀,如果被指定,[pathname][string] 中的 [suffix] 会被去掉

dirname 返回目录名

返回完整路径最后 / 前面的部分,常用于返回路径部分,不包含最后一个 /
dirname 文件绝对路径 从给定的文件绝对路径保留目录部分并返回

Shell 自定义函数

基本语法

function funname()
{
        # 函数体
        # 可以通过 echo 的方式返回
}

# 函数调用
funname 值1 值2 ...
#!/bin/bash

function getSum() {
        SUM=$[$n1+$n2]
        echo "SUM=$SUM"
}

read -p "NUM1 " n1
read -p "NUM2 " n2

getSum $n1 $n2

Shell 编程综合案例

#!/bin/bash

# 每天凌晨 2:30 备份数据库 my_database 到 /data/backup/db
# 备份开始和结束有提示信息
# 文件名为备份时间,格式 .tar.gz
# 删除10天以上的备份文件

# 备份目录
BACKUP=/data/backup/db
# 获取当前时间
DATETIME=$(date +%Y-%m-%d_%H%M%S)
echo $DATETIME
# 数据库地址
HOST=localhost
# 数据库用户名
DB_USER=root
# 数据库密码
DB_PW=root
# 备份的数据库
DATABASE=my_database

# 创建备份目录
[ ! -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} 成功"