- A+
所属分类:linux技术
Shell脚本
Shell是什么?
- Shell脚本语言属于弱类型语言,解析用户输入的命令和程序,使得用户可以与Linux进行交互;
- 适合处理纯文本类型数据(日志、配置文件、文本、网页文件、大多数纯文本类型的文件)。
Shell概念
shebang
-
即文件的第一行前两个字符
#!
,后面的语句指定命令的解析器。#!/bin/sh 或 #!/bin/bash
:执行时会调用/bin/sh
,即bash
解析器。#!/bin/perl
:执行时。#!/usr/bin/python
:python
解析器。#!/usr/bin/env
:跨平台都能正常找到解析器的办法。- 注意:
- 未指定
shebang
时,默认用Shell
解析。 - 当指定
shebang
,但程序是不可执行文件时,转而用Shell
解析。 - 指定
shebang
解析器的路径需要绝对路径。 - 执行时指定解析器执行,会忽略
shebang
解析器。
- 未指定
变量
- 命名规则: 只能数字、字母、下划线,不能以数字开头,区分大小写。
- 数据类型:bash默认所有变量都是字符串。
- 作用域:只针对当前的Shell进程,每次调用
bash/sh
解析器执行脚本都会开启一个子Shell
。 - 进程树:
# psTree 可以检查进程树 pstree ps -ef --forest
常用命令
# 转义 echo "print each param from "$*"" # 变量定义与赋值之间不得有空格 name="I am Soul!" # 单引号不识别特别语法,双引号识别特殊符号 name2="${name}" # 变量替换/引用 echo ${name} echo $name # 转义 即 变量中定义命令 name = `ls` # 1)执行 name 变量时实际上是输出 ls 指令 echo $name # 常用命令 set # 输出所有变量(局部、全局) unset 变量名 # 删除变量/函数 env # 输出全局变量 declare # 输出所有变量 export # 输出/设置环境变量 export | awk -F '[ :=]' '{print $3}' # 输出系统环境变量关键字 readonly # 设置只读 let # 数值运算 即 (()) expr # 计算器 expr yn.png ":" ".*" # 统计 yn.png 文件字符个数 test -e soul.jpg && echo "OK" || echo "NO" # 三目运算
环境变量
- 常用环境变量
${USER} # 当前用户名字 $UID # 当前用户ID $HOME # 当前用户文件目录 $(data) # 时间
- 配置文件
# 用户个人配置 ~/.bash_profile ~/.bashrc # 远程登录用户特有文件 # 全局配置文件 /etc/profile /etc/bashrc /etc/profile.d/ # 系统建议创建在该目录而非直接修改全局配置文件。
- 环境变量文件加载顺序
特殊变量
# 特殊参数变量 $0 # 获取Shell脚本文件名,以及脚本路径 $n # 获取脚本的第n个参数(n>=1),当大于9时,需要写成 ${10} $# # 获取执行的Shell脚本后面的参数的总数 $* # 获取Shell脚本所有参数,加双引号时,将所有参数视为一份数据 $@ # 获取Shell脚本所有参数,加双引号时,仍然将每个参数视为独立的数据 # 特殊状态变量 $? # 上一次执行命令的状态返回值:0:成功,否则失败。 $$ # 当前Shell脚本的进程号 $! # 上一次后台进程的PID $_ # 获取上一次执行命令最后一个参数
扩展变量
${parameter:-word} # param参数为空时返回word值 ${parameter:=word} # param参数为空时将word值返回给param参数并作为返回值 ${parameter:?word} # param参数为空时返回word作为提示信息返回 ${parameter:+word} # param参数为空时不做处理,否则返回word
bash的内置命令
echo -n # 不换行输出 echo -e # 解析字符串中的特殊字符(n:换行,r:回车,t:制表符,b:退格) echo $name | wc -l # 统计有多少行 echo $name | wc -L # 统计长度 echo "8.8*2" | bc # 执行 bc 运算 eval ls;cd /tmp # 执行多个命令 exec # 不创建子进程,执行后续命令,且执行完毕后自动退出 seq # 生成序列指令 seq -s ":" 10 # 生成 1~10的序列并用分号隔开 time # 计算执行时间 read -t 5 -p "请输入:" # 提示用户,输入信息(-p),-t 超时时间 # 运算 # 1) 求和运算 echo {1..100} | tr " " "+" | bc # 求和运算 echo $((`seq -s "+" 100`)) # (()) seq -s " + " 100 | xargs expr # xargs expr # 2)awk方式运算 echo "3.2 2.2" | awk '{print $1+$2}' # 测试 test [ ] # 也可以用中括号 [ ] 代替test,前后必须有空格,变量必须用"" test -e a.txt -a -f a.txt # -a 即: and && 条件 test -e a.txt -o -f a.txt # -o 即: or || 条件 # 1) 文件相关 test -e # 文件是否存在 test -f # 是否为文件 test -d # 是否为目录 test -r # 文件是否有[可读]属性 test -w # 文件是否有[可写]属性 test -x # 文件是否有[可执行]属性 # 2)字符串 test -z # 字符串为空时为真,否则为假。 test -n # 字符串为空时为假,否则为真。 # 3)比较 test -eq # 两个数值相等 test -nq # 两个数值不相等 test -gt # a 大于 b test -lt # a 小于 b test -ge # a 大于等于 b test -le # a 小于等于 b test = # test != # test ! #
shell子串
${name} # 返回变量值 ${#name} # 返回变量长度,字符串长度 ${name:start} # 从第几位截取返回子字符串 ${name:start:length} # 从第几位开始,长度为length进行截取 ${name#word} # 从变量开头删除最短的word字符串 ${name##word} # 从变量开头删除最长word字符串 ${name%word} # 从变量结尾删除最短的word字符串 ${name%%word} # 从变量结尾删除最长的word字符串 ${name/pattern/string} # 用string替换第一个匹配的pattern ${name//pattern/string} # 用string替换所有的pattern # 统计子串长度 echo ${#name} # 返回长度(最快) echo $name | wc -l # wc 统计有多少行 echo $name | wc -L # wc 统计长度 expr length "${name}" # expr 计算数值 echo $name | awk '{print length($0)}' # awk 统计长度,length函数
执行方式
# 进程列表,并在子进程运行 (cd ~;pwd;ls;cd /tmp/;pwd;echo $BASH_SUBSHELL) # 利用()括号开启子进程执行命令,$BASH_SUBSHELL检查当前进程层数(子进程大于1),常用于多进程处理提高程序并发执行的效率。 # 方式一(常用): 文件没有执行权限 或 脚本没有指定 shebang 都可以执行,会开启子进程执行Shell(获取不了当前进程的变量) bash script.sh sh script.sh # 方式二:绝对/相对路径执行脚本,需要文件含有X权限。 bash /usr/script.sh bash .script.sh # 方式三:不会开启子进程执行Shell,可以获取当前进程的变量。 source script.sh . script.sh # 方式四: sh < script.sh
Shell脚本应用
批量操作文件名
# 批量创建文件 touch soul_config{1..2}.xml # 批量修改文件名 for item in `ls *config.xml` # 获取当前目录下部分后缀的文件名 do mv $item `echo ${item//config/}` # 将config文件名替换为空 done
数据备份并删除过期数据
# find xargs find ${dir_path:=/data/mysql_back_data/} -name '*.tar.gz' -type f -mtime +7 | xargs rm -f # 避免dir_path为空时取指定路径下的数据
运算脚本开发
#!/bin/bash/ # 开发一个 运算脚本 # 定义打印函数 print_soul(){ printf "Please enter an interger!n" exit 1 } # 接收用户输入的第一个数字 read -p "Please input your number: " firstnum # [] 中括号前后必须有空格 # -n 判断条件是否为空字符串 # sed 将所有数字替换为空 if [ -n "`echo $firstnum|sed 's/[0-9]//g'`" ]; then print_soul fi # 接收用户输入的 运算符 read -p "Please input your operator:" operator if [ "${operator}" != "+" ] && [ "${operator}" != "-" ] && [ "${operator}" != "/" ] && [ "${operator}" != "*" ]; then echo "只允许 输入 + | - | * | /" exit 2 fi # 接收用户输入的第二个数字 read -p "Please input your number: " sencondnum if [ -n "`echo ${sencondnum} | sed 's/[0-9]//g'`" ]; then print_soul fi # 运算 echo "${firstnum}${operator}${sencondnum}结果是:" $((${firstnum}${operator}${sencondnum}))
Nginx存活检测
#!/bin/bash/ # 失败次数 fails=0 success=0 # 空转检查 while true do # 请求网站是否能打开 wget --timeout=5 --tries=1 http://baidu.com/ -q -0 /dev/null # -ne 不等于 if [ $? -ne 0 ]; then let fails=fails+1 else let success+=1 fi # -ge 大于,网站正常 if [ $success -ge 1 ]; then echo "The inter site is Ok!!!" exit 0 fi # -ge 大于,网站异常、并发送邮件 if [ $fails -ge 2 ]; then mail -s "`date +%F-%T`" 16042334@qq.com "The inter site is fails!!!" exit 2 fi done
Mysql存活检测
#!/bin/bash/ # netstat、ss、lsof 三种方式检查Mysql是否运行、失败即发送邮件提醒。 # 邮件发送,需要配置:vim /etc/mail.rc,配置发送者的账号信息 if [ `netstat -tunlp | grep mysql | wc -l` != "1" -a `ss -tunlp | grep mysql | wc -l` -nq "1" -a `lsof -i tcp:3306 | wc -l` = "0" ];then mail -s "`date +%F-%T`" 16042334@qq.com "The mysql is stopped!!!" fi
Mysql备份
#!/bin/bash/ DATE=$(date +%F_%H-%M-%S) HOST=localhost USER=backup PASS=123.com BACKUP_DIR=/data/db_backup DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2> /dev/null | egrep -v "Database|information_schema|mysql|performance_schema|sys") for item in $DB_LIST; do BACKUP_NAME=${BACKUP_DIR}/${DB}_${DATE}.sql if ! mysqldump -h$HOST -u$USER -p$PASS -B $DB > ${BACKUP_NAME} 2> /dev/null;then echo "$BACKUP_NAME is Backup failed !!!" fi done