shell脚本编程
shell概述
什么是shell:shell是Linux内核与用户之间的解释器程序,通常指bash,负责向内核翻译及传达用户/程序指令,相当于操作系统的“外壳”。
切换解释器:如果需要使用另一种解释器,可以直接执行对应的shell解释器程序,比如可以通过sh指令切换到sh命令行环境。管理员也可以通过usermod修改用户的登陆shell。当前系统可使用的shell程序存放在/etc/shells中。
bash基本特性
- 支持快捷键、tab补全
- 支持历史命令
- 支持别名
- 支持标准输入输出
- 支持重定向
- 支持管道
shell的使用方式
- 交互式:人工干预,执行效率低
- 非交互式:安静的在后台执行,效率高,方便编写脚本
shell脚本
shelll脚本指提前写好的可执行语句,可以完成特定任务的文件
特点:
- 顺序、批量化执行
- 解释型程序
规范的脚本构成:
#!/bin/bash #脚本声明(声明使用解释器类型)
#注释信息
echo "hello world" #可执行的脚本语句或命令行
脚本的执行方式:
-
作为“命令字”
必须在脚本有x权限的前提下,通过
./脚本名
执行该脚本 -
作为“参数”
- bash 脚本解释器
- source 脚本解释器
- . 脚本解释器
调试shell脚本:
- 直接观察执行中的输出、报错信息
- 通过sh -x 开启调试模式
- 在可能出错的地方设置echo
简单的脚本应用
搭建本地yum服务
#!/bin/bash
#create yum service
[ ! -e /dev/cdrom ] && echo 'image not exists'
mount /dev/cdrom /media &> /dev/null
#backup file
[ ! -d /etc/yum.repos.d/backup ]&&mkdir /etc/yum.repos.d/backup
[ -f /etc/yum.repos.d/ ]&&mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup
#edit '.repo' file
echo '
[app]
baseurl=file:///media/AppStream
gpgcheck=0
[base]
baseurl=file:///media/BaseOS
gpgcheck=0
'> /etc/yum.repos.d/dvd.repo
#yum test
yum clean all &> /dev/null
yum repoinfo &> /dev/null
[ $? -ne 0 ] && echo 'create yum filed' && exit
echo 'create yum successfully'
搭建ftp服务
#!/bin/bash
yum -y install vsftpd &> /dev/null
systemctl restart vsftpd
systemctl enable vsftpd
echo 'vsftpd start successfully'
shell变量
定义:以固定的名称存放可能会变化的值,
优点:
- 提高脚本对任务需求、运行环境变化的适应能力
- 方便在脚本中重复使用
变量操作:
-
定义/赋值
变量名=变量值
- 变量未赋值时默认为空
- 如果变量名已存在,再次赋值相当于重新为变量赋值
- 等号两边不能有空格
- 变量名由数字、字母、下划线组成,且区分大小写
- 变量名不能以数字开头,不能使用关键字和特殊字符
-
查看变量
- 引用变量值:
$变量名
- 查看变量值:
echo $变量名
、echo ${变量名}
(${变量名}可以将变量名和其前后的字符分隔开来)
- 引用变量值:
-
取消变量
- 推出定义变量的shell环境时,变量会自动消失
unset 变量名
可以手动取消变量
变量的类型:
-
按存储类型分类:
- 整形、浮点型、双精度浮点型、字符型、...
- shell对存储类型的要求比较松散
-
按使用类型分类:
-
环境变量:变量名通常为大写,由系统维护,用于设置工作环境,只有个别变量用户可以直接更改
相关操作:
- env:列出所有环境变量
- set:列出所有变量
- 配合grep使用
常见环境变量:PWD、PATH、USER、LOGNAME、UID、SHELL、HOME、PS1、PS2...
-
位置变量:bash内置,存储执行脚本是提供的参数
用
$n
表示,n为序号,在执行脚本时提供的命令行参数 -
预定义变量:bash内置,一类有特殊用途的变量,可以直接调用,但不能直接赋值或修改
$0:当前所在的进程或脚本名
$$:当前运行进程的PID
$?:命令执行后的返回状态,0为正常,非0为异常
$#:已加载的位置变量的个数
$*:所有位置变量的值
-
自定义变量:由用户自主设置、修改及使用
-
变量值及范围控制
三种定界符:
- 双引号:
""
: 允许使用扩展,以$引用其他变量 - 单引号:
''
:禁用扩展,所有特殊字符都视为普通字符 - 反撇号:
``
:将命令运行结果输出。
read标准输入取值
-
read 从键盘读入变量值完成赋值:
格式:
read [-p "提示信息"] 变量名
-p可输入提示信息,-t可指定超时秒数。
-
终端显示控制:
stty -echo:关闭终端输出(无显示)
stty echo:恢复终端输出(显示)
可以用来在输入密码时屏蔽密码显示。
变量的作用范围
局部变量只能在当前shell环境中使用,进入子shell后无法使用。
可以通过export 变量名
将变量声明为全局变量,通过export -n 变量名
取消全局变量。
数值运算
基本运算类型:
加:num1 + num2
减:num1 - num2
乘:num1 * num2
除:num1 / num2
求模:num1 % num2
运算工具
-
expr:
格式:
expr 整数1 运算符 整数2
注:
- 乘法操作应采用\*转义,避免被shell当作通配符。
- expr只能用与整数运算,计算结果均只保留整数位。
-
$[]运算替换
使用$[]或$(())表达式可以直接得出计算结果
格式:
$[整数1 运算符 整数2]
注:
- 乘法操作无需转义
- 可以与echo结合,输出计算结果
- 只能进行整数运算
-
let实现变量的自增减
let i++ #i+1
let i-- #i-1
let i*=2 #i=i*2
... -
bc:
- 支持小数运算
- 通过
scale=n
指定小数的位数 echo "scale=4;10/3;2.2*4.1" | bc
通过echo输出多个表达式的计算结果
逻辑判断
语法:test 选项 参数
或[ 选项 参数 ]
常见的测试操作:
-
字符串比较
[ 操作符 字符串 ]
操作符:
-z
判断字符串的值为空;-n
判断字符串的值非空==
两个字符串相同;!=
两个字符串不同 -
整数值比较
[ 整数1 操作符 整数2 ]
-eq
等于-ne
不等于-ge
大于等于-le
小于等于-gt
大于-lt
小于 -
文件状态测试
[ 操作符 文件或目录 ]
-e
判断是否存在-d
判断是否是目录-f
判断是否是一般文件-r
判断是否有读权限-w
判断是否有写权限-x
判断是否有可执行权限
循环
格式:
-
单分支结构
if 条件测试;then
命令序列
fi
-
双分支结构
if 条件测试;then
命令序列1
else
命令序列2
fi
-
多分支结构
if 条件测试1;then
命令序列1
elif 条件测试2;then
命令序列2
else
命令序列3
fi
相关练习
-
检测/if_test/cdrom/目录是否存在,不存在则创建
#!/bin/bash dir=/if_test/cdrom/ if [ -d $dir ];then echo ${dir} exist. && exit else mkdir -p $dir fi
-
编写脚本,检测并判断指定的主机是否可ping通
#!/bin/bash # ping命令个参数作用:可以只发送3个测试包(-c 3)、缩短发送测试包的间隔秒数(-i 0.2)、等待反馈的超时秒数(-W 1) ip=192.168.99.100 ping -c3 -i 0.2 -W 1 $ip &> /dev/null if [ $? -eq 0 ];then echo 'host $1 is up' else echo 'host $1 is down' fi
-
判断成绩
#!/bin/bash read -p 'press your grade: ' n if [ $n -gt 100 ] || [ $n -lt 0 ];then echo 'press a number(0-100)' && exit elif [ $n -ge 90 ];then echo great elif [ $n -ge 80 ];then echo nice else echo good fi
循环
for循环:
-
格式:
for 变量名 in 值列表
do
命令序列
done
-
c语言风格:
for((i=1;i<=5;i++))
do
命令序列
done
练习
-
写一个Shell脚本chkhosts.sh,利用for循环来检测多个主机的存活状态,并显示最后统计结果
#!/bin/bash up=0 down=0 for i in {100..110} do ping -c 3 -i 0.2 -w 1 192.168.99.$i &> /dev/null if [ $? -eq 0 ];then let up++ else let down++ fi done echo $up echo $down
while循环:
-
格式:
while 条件测试
do
命令序列
done
while死循环
-
格式:
while :
do
命令序列
done
中断及退出
- exit:退出整个脚本
- break:结束当前循环,继续执行循环之后的语句
- continue:跳过本次循环中剩余语句
练习
-
从键盘循环取整数(0结束)并求和,输出最终结果
#!/bin/bash sum=0 while : do read -p 'press a number: ' n if [ -z $n ];then continue elif [ $n -eq 0 ];then break else let sum+=n fi done echo sum=$sum
case语句
-
语法
case 变量 in 模式1) 命令序列1 ;; 模式2) 命令序列2 ;; .. .. *) 默认命令序列 esac
-
练习
编写一键部署Nginx脚本
- 一键源码安装Nginx软件
- 脚本自动安装相关软件的依赖包
- 源码安装Nginx需要提前安装依赖包软件gcc,openssl-devel,pcre-devel
#!/bin/bash yum -y install gcc openssl-devel pcre-devel tar -xf nginx-1.22.1.tar.gz cd nginx-1.22.1 ./configure make make install
编写Ngin启动脚本,要求如下:
- 脚本支持start、stop、restart、status
- 脚本支持报错提示
- 脚本具有判断是否已经开启或关闭的功能
-
#!/bin/bash case $1 in start|kai) /usr/local/nginx/sbin/nginx;; stop|guan) /usr/local/nginx/sbin/nginx -s stop;; restart|cq) /usr/local/nginx/sbin/nginx -s stop /usr/local/nignx/sbin/nginx;; status|zt) ss -ntulp |grep -q nginx if [ $? -eq 0 ];then echo 服务已启动 else echo 服务未启动 fi;; *) echo Error;; esac
函数
-
函数格式
# 格式1 function 函数名 { 命令序列 .. .. } # 格式2 函数名() { 命令序列 .. .. }
-
函数调用
直接使用“函数名”的形式调用,如果该函数能够处理位置参数,则可以使用“函数名 参数1 参数2 .. ..”的形式调用。
注意:函数的定义语句必须出现在调用之前,否则无法执行。
-
练习
用户在执行时提供2个整数参数,这个可以通过位置变量$1、$2读入。
调用函数时,将用户提供的两个参数传递给函数处理。
颜色输出的命令:echo -e "\033[32mOK\033[0m"。
3X为字体颜色,4X为背景颜色。
#!/bin/bash #echo -e "\033[$1m$2\033[0m"中$1表示显示输出文本的颜色。3X为字体颜色,4X为背景颜色 cecho(){ echo -e "\033[$1m$2\033[0m" } cecho 32 ok cecho 33 ok
字符串操作
-
字符串的截取
格式:
${var:起始位置:长度}
-
字符串的替换
格式:只替换第一个匹配的结果
${var/old/new}
替换全部匹配结果:
${var//old/new}
-
掐头
-
从左往右,最短匹配删除
格式:
${变量名#*关键词}
-
从左往右,最长匹配删除
格式:
${变量名##*关键词}
-
-
去尾
-
从右往左,最短匹配
格式:
${变量名%关键词*}
-
从右往左,最长匹配
格式:
${变量名%%关键词*}
-
-
设置变量初值
格式:
${var:-word}
若var已存在,且非空,则返回$var的值
否则返回字符串‘word’,变量var值不变。
sed入门
未完待续。。。
awk入门
未完待续。。。