Shell脚本(三)-------------Shell编程

shell脚本学习系列(三)
上一篇: Bash变量与环境配置文件
下一篇:


2.Shell编程

  • 2.1正则表达式
  • 2.1.1正则表达式与通配符

    正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配。grep、awk、sed等命令可以支持正则表达式。
    通配符用来匹配符合条件的文件名,通配符是完全匹配。
    ls、find、cp这些命令不支持正则表达式,所以只能使用shell自己的通配符来进行匹配了。
    
  • 2.1.2基础正则表达式
    这里写图片描述

  • 2.2字符截取命令

  • 2.2.1cut命令

[root@localhost ~]# cut [选项] 文件名
选项:
-f 列号:  提取第几列
-d 分隔符: 按照指定分隔符分割列

cut命令的局限:不能很好的支持以不同数量的空格为分隔符
  • 2.2.2printf命令
printf ’输出类型输出格式’ 输出内容

输出类型:
%ns:  输出字符串。n是数字指代输出几个字符
%ni:  输出整数。n是数字指代输出几个数字
%m.nf:  输出浮点数。m和n是数字,指代输出的整数位数和小数位数。如%8.2f代表共输出8位数,其中2位是小数,6位是整数。

输出格式:
\a: 输出警告声音
\b: 输出退格键,也就是Backspace键
\f: 清除屏幕
\n: 换行
\r: 回车,也就是Enter键
\t: 水平输出退格键,也就是Tab键
\v: 垂直输出退格键,也就是Tab键

示例:

[root@localhost ~]# printf %s 1 2 3 4 5 6
123456
[root@localhost ~]# printf %s %s %s 1 2 3 4 5 6
%s%s123456
[root@localhost ~]# printf '%s %s %s' 1 2 3 4 5 6
1 2 34 5 6
[root@localhost ~]# printf '%s %s %s\n' 1 2 3 4 5 6
1 2 3 
4 5 6
  • 2.2.3awk命令

用于提取字符串列

# awk ‘条件1{动作1} 条件2{动作2}…’ 文件名

条件(Pattern):
一般使用关系表达式作为条件
x > 10  判断变量 x是否大于10
x>=10  大于等于
x<=10  小于等于
动作(Action):
格式化输出
流程控制语句

示例:

# awk '{printf $2 "\t" $6 "\n"}' student.txt
# df -h | awk '{print $1 "\t" $3}'

# awk 'BEGIN{printf "This is a transcript \n" }{printf $2 "\t" $6 "\n"}' student.txt
# awk 'END{printf "The End \n" }{printf $2 "\t" $6 "\n"}' student.txt
# cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=":"} {printf $1 "\t" $3 "\n"}'

BEGIN:初始化标志
END:数据处理完成后
FS:指定分隔符

关系运算符
# cat student.txt | grep -v Name | awk '$6 >= 87 {printf $2 "\n" }'
  • 2.2.4sed命令

sed 是一种几乎包括在所有 UNIX 平台(包括 Linux)的轻量级流编辑器。sed主要是用来将数据进行选取、替换、删除、新增的命令。

[root@localhost ~]# sed [选项] ‘[动作]’ 文件名

选项:
-n: 一般sed命令会把所有数据都输出到屏幕 ,如果加入此选择,则只会把经过sed命令处理的行输出到屏幕。
-e: 允许对输入数据应用多条sed命令编辑
-i: 用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出
动作:
a \: 追加,在当前行后添加一行或多行。添加多行时,除最后 一行外,每行末尾需要用“\”代表数据未完结。
c \: 行替换,用c后面的字符串替换原数据行,替换多行时,除最后一行外,每行末尾需用“\”代表数据未完结。
i \: 插入,在当期行前插入一行或多行。插入多行时,除最后 一行外,每行末尾需要用“\”代表数据未完结。
d: 删除,删除指定的行。
p: 打印,输出指定的行。
s: 字串替换,用一个字符串替换另外一个字符串。格式为“行范围s/旧字串/新字串/g”(和vim中的替换格式类似) 。
  • 2.2.4.1行数据处理
[root@localhost ~]# sed '2p' student.txt
#查看文件的第二行

[root@localhost ~]# sed -n '2p' student.txt
[root@localhost ~]# sed '2,4d' student.txt
# 删除第二行到第四行的数据,但不修改文件本身

[root@localhost ~]# sed '2a hello' student.txt
# 在第二行后追加 hello

[root@localhost ~]# sed '2i hello world' student.txt
# 在第二行前插入两行数据

# sed '2c No such person‘ student.txt
# 数据替换
  • 2.2.4.2字符串替换
# sed ‘s/旧字串/新字串/g’ 文件名
# sed '3s/74/99/g' student.txt
# 在第三行中,把 74 换成 99

#sed -i '3s/74/99/g' student.txt
#sed操作的数据直接写入文件

# sed -e 's/Liming//g ; s/Gao//g' student.txt
# 同时把“ Liming ”和“ Gao ”替换为空
  • 2.3字符处理命令
  • 2.3.1排序命令sort
[root@localhost ~]# sort [选项] 文件名
选项:
-f: 忽略大小写
-n: 以数值型进行排序,默认使用字符串型排序
-r: 反向排序
-t: 指定分隔符,默认是分隔符是制表符
-k n[,m]: 按照指定的字段范围排序。从第n字段开始,m字段结束(默认到行尾)

[root@localhost ~]# sort /etc/passwd
# 排序用户信息文件

[root@localhost ~]# sort -r /etc/passwd
# 反向排序

[root@localhost ~]# sort -t ":" -k 3,3 /etc/passwd
# 指定分隔符是“:”,用第三字段开头,第三字段结尾排序,就是只用第三字段排序

[root@localhost ~]# sort -n -t ":" -k 3,3 /etc/passwd
  • 2.3.2统计命令wc
[root@localhost ~]# wc [选项] 文件名
选项:
-l:  只统计行数
-w:  只统计单词数
-m:  只统计字符数
  • 2.4条件判断

按照文件类型进行判断
这里写图片描述

示例

两种判断格式
[root@localhost ~]# test -e /root/install.log

[root@localhost ~]# [ -e /root/install.log ]

[ -d /root ] && echo "yes" || echo "no"
# 第一个判断命令如果正确执行,则打印“ yes ”,否则打印“ no ”
  • 2.4.2按照文件权限进行判断
    这里写图片描述

示例:

[ -w student.txt ] && echo "yes" || echo "no"
# 判断文件是拥有写权限的
  • 2.4.3两个文件之间进行比较
    这里写图片描述
    示例:
ln /root/student.txt /tmp/stu.txt
# 创建个硬链接吧
[ /root/student.txt -ef /tmp/stu.txt ] && echo "yes" || echo "no" 
# 用 test 测试下,果然很有用
输出结果:yes
  • 2.4.4两个整数之间比较
    这里写图片描述
    示例:
[ 23 -ge 22 ] && echo "yes" || echo "no"
yes
# 判断 23 是否大于等于 22 ,当然是了

[ 23 -le 22 ] && echo "yes" || echo "no"
no
# 判断 23 是否小于等于 22 ,当然不是了
  • 2.4.5字符串的判断
    这里写图片描述

    示例:

name=sc
# 给 name 变量赋值
[ -z "$name" ] && echo "yes" || echo "no"
no
# 判断 name 变量是否为空,因为不为空,所以返回 no

aa=11
bb=22
# 给变量 aa 和变量 bb 赋值
[ "$aa" == "bb" ] && echo "yes" || echo "no"
no
# 判断两个变量的值是否相等,明显不相等,所以返回 no
  • 2.4.6多重条件判断
    这里写图片描述

示例:

aa=11
[ -n "$aa" -a "$aa" -gt 23 ] && echo "yes" || echo "no"
no
# 判断变量 aa 是否有值,同时判断变量 aa 的是否大于 23
# 因为变量 aa 的值不大于 23 ,所以虽然第一个判断值为真,返回的结果也是假

aa=24
[ -n "$aa" -a "$aa" -gt 23 ] && echo "yes" || echo "no"
yes
  • 2.5流程控制
  • 2.5.1If语句
  • 2.5.1.1单分支if条件语句
if [ 条件判断式 ];then
程序
fi

或者

if [ 条件判断式 ]
then
程序
fi

单分支条件语句需要注意几个点

if语句使用fi结尾,和一般语言使用大括号结尾不同
[ 条件判断式 ]就是使用test命令判断,所以中括号和条件判断式之间必须有空格then后面跟符合条件之后执行的程序,
可以放在[]之后,用“;”分割。也可以换行写入,就不需要“;”了

例子:判断分区使用率

#!/bin/bash
#统计根分区使用率
# Author: shenchao (E-mail: [email protected]
rate=$(df -h | grep "/dev/sda3" | awk '{print $5}' | cut -d "%" -
f1)
#把根分区使用率作为变量值赋予变量 rate
if [ $rate -ge 80 ]
then
echo "Warning! /dev/sda3 is full!!"
fi
  • 2.5.1.2双分支if条件语句
if [ 条件判断式 ]
then
条件成立时,执行的程序
else
条件不成立时,执行的另一个程序
fi

例子1:备份mysql数据库

#!/bin/bash
#备份 mysql 数据库。
# Author: shenchao (E-mail: [email protected]
ntpdate asia.pool.ntp.org &>/dev/null
#同步系统时间
date=$(date +%y%m%d)
#把当前系统时间按照“年月日”格式赋予变量 date
size=$(du -sh /var/lib/mysql)
#统计 mysql 数据库的大小,并把大小赋予 size 变量
if [ -d /tmp/dbbak ]
then
echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
cd /tmp/dbbak
tar  -zcf  mysql-lib-$date.tar.gz  /var/lib/mysql  dbinfo.txt &>/dev/null 
rm -rf /tmp/dbbak/dbinfo.txt
else
mkdir /tmp/dbbak
echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
cd /tmp/dbbak
tar  -zcf  mysql-lib-$date.tar.gz  /var/lib/mysql  dbinfo.txt &>/dev/null
rm -rf /tmp/dbbak/dbinfo.txt
fi

例子2:判断apache是否启动

#!/bin/bash
# Author: shenchao (E-mail: [email protected]
port=$(nmap -sT 192.168.1.156 | grep tcp | grep http | awk '{print $2}')
#使用nmap命令扫描服务器,并截取apache服务的状态,赋予变量port
if [ "$port" == "open" ]
then
echo “$(date) httpd is ok!” >> /tmp/autostart-acc.log
else
/etc/rc.d/init.d/httpd start &>/dev/null
echo "$(date) restart httpd !!" >> /tmp/autostart-err.log
fi
  • 2.5.1.3多分支if条件语句
if [ 条件判断式1 ]
then
当条件判断式1成立时,执行程序1
elif [ 条件判断式2 ]
then
当条件判断式2成立时,执行程序2
„省略更多条件 …
else
当所有条件都不成立时,最后执行此程序
fi
#!/bin/bash
#判断用户输入的是什么文件
# Author: shenchao (E-mail: [email protected]
read -p "Please input a filename: " file
#接收键盘的输入,并赋予变量 file
if [ -z "$file" ]
#判断 file 变量是否为空
then
echo "Error,please input a filename"
exit 1
elif [ ! -e "$file" ]
#判断 file 的值是否存在
then
echo "Your input is not a file!"
exit 2
elif [ -f "$file" ]
#判断 file 的值是否为普通文件
then
echo "$file is a regulare file!"
elif [ -d "$file" ]
#判断 file 的值是否为目录文件
then
echo "$file is a directory!"
else
echo "$file is an other file!"
fi
  • 2.5.2Case语句

    case语句和if…elif…else语句一样都是多分支条件语句,不过和if多分支条件语句不同的是,case语句只能判断一种条件关系,而if语句可以判断多种条件关系。

case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
#!/bin/bash
#判断用户输入
# Author: shenchao (E-mail: [email protected]

read -p "Please choose yes/no: " -t 30 cho
case $cho in
"yes")
echo "Your choose is yes!"
;;
"no")
echo "Your choose is no!"
;;
*)
echo "Your choose is error!"
;;
esac
  • 2.5.3For循环
  • 2.5.3.1语法一
for 变量 in123do
程序
done
#!/bin/bash
#打印时间
# Author: shenchao (E-mail: [email protected]
for time in morning noon afternoon evening
do
echo "This time is $time!"
done
#!/bin/bash
#批量解压缩脚本
# Author: shenchao (E-mail: [email protected]
cd /lamp
ls *.tar.gz > ls.log
for i in $(cat ls.log)
do
tar -zxf $i &>/dev/null
done
rm -rf /lamp/ls.log
  • 2.5.3.2语法二
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
#!/bin/bash
# 从 1 加到 100
# Author: shenchao (E-mail: [email protected]
s=0
for (( i=1;i<=100;i=i+1 ))
do
s=$(( $s+$i ))
done
echo "The sum of 1+2+...+100 is : $s"
#!/bin/bash
#批量添加指定数量的用户
# Author: shenchao (E-mail: [email protected]
read -p "Please input user name: " -t 30 name
read -p "Please input the number of users: " -t 30 num
read -p "Please input the password of users: " -t 30 pass
if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]
then
y=$(echo $num | sed 's/[0-9]//g')
if [ -z "$y" ]
then
for (( i=1;i<=$num;i=i+1 ))
do
 /usr/sbin/useradd $name$i &>/dev/null
echo $pass | /usr/bin/passwd --stdin $name$i &>/dev/null
done
fi
fi
  • 2.5.4While循环与until循环
  • 2.5.4.1while循环

while循环是不定循环,也称作条件循环。只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。这就和for的固定循环不太一样了。

while [ 条件判断式 ]
do
程序
done
#!/bin/bash
#从1加到100
# Author: shenchao (E-mail: [email protected]
i=1
s=0
while [ $i -le 100 ]
#如果变量 i 的值小于等于 100 ,则执行循环
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo "The sum is: $s"
  • 2.5.4.2until循环

until循环,和while循环相反,until循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。

until [ 条件判断式 ]
do
程序
done
#!/bin/bash
#从1加到100
# Author: shenchao (E-mail: [email protected]
i=1
s=0
until [ $i -gt 100 ]
#循环直到变量 i 的值大于 100 ,就停止循环
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo "The sum is: $s"

shell脚本学习系列(三)
上一篇: Bash变量与环境配置文件
下一篇:

猜你喜欢

转载自blog.csdn.net/AGambler/article/details/82051065