您的位置:首页 > 运维架构 > Shell

脚本入门:shell变量和条件测试

2016-08-13 14:55 741 查看
写脚本是运维行业中最有趣的一部分(我是这么觉得),一个功能强大的脚本可以省去许多的时间(如果以后都是自动化运维,我们该干什么呢?)。脚本的用途主要有:自动化处理、执行系统管理和故障排除、一键部署管理应用程序、批量处理文本文件。
shell是一个解释型的脚本语言,它有一定的格式规范,bashshell是主流Linux的默认shell,在shell脚本的首行一般都有shebang机制,即首行会写上使用哪一个shell解释器,当给脚本赋予执行权限并执行时,Linux将根据这里指定的shell去解释执行。当然也可以直接将脚本文件当作参数给shell去执行,这时就不必要写shebang了。
[root@localhost ~]# bash test.sh
1
[root@localhost ~]# ./test.sh
1
一、shell变量和其他编程语言的变量一样,变量是指向一段内存空间的字符串。shell是弱类型的语言,使用变量前不必首先声明,shell默认所有变量都是字符类型的。变量命名:良好的命名习惯可以方便团队协作,能让以后的工作人员在已有的脚本上进行扩展从而节省了运维成本变量名只能用字母、数字和下划线组成,数字不能作为变量名的开头命名采用驼峰法以免出现歧义,要做到见名知意,变量名不能使用保留字
shell变量类型:按照变量的内容可以分为:字符型和数值型字符型:数值型:按照变量的作用范围分:本地变量:变量只对当前shell生效
[root@localhost bin]# cat test1.sh
#!/bin/bash
var1="this is test1"
bash /testdir/bin/test2.sh
[root@localhost bin]# cat test2.sh
#!/bin/bash
echo $var1
[root@localhost bin]# bash test1.sh
[root@localhost bin]#
可以看到执行test1.sh没有任何输出
环境变量:只对当前shell及其子shell有效,对父shell无效。

变量声明、赋值
export name=value 或declare -x name=value,也可以声明本地变量后用export和declare -x转换为环境变量.
引用方式和本地变量一样
如果要显示所有环境变量可用:export、env、printenv或declare -x

删除环境变量:unset name
[root@localhost bin]# cat testenv.sh
#!/bin/bash
env1="this is a env test"
name="this is a local variable"
export env1
./testenv2.sh
[root@localhost bin]# cat testenv2.sh
#!/bin/bash
echo $env1
echo $name
[root@localhost bin]# bash testenv.sh
this is a env test

[root@localhost bin]#

只读变量:声明后无法修改和删除

变量声明:readonly name或declare -r name,只读变量在退出当前shell时失效
[root@localhost bin]# name="readonly"
[root@localhost bin]# readonly name
[root@localhost bin]# echo $name
readonly
[root@localhost bin]# name="hello"
-bash: name: readonly variable
[root@localhost bin]# unset name
-bash: unset: name: cannot unset: readonly variable
[root@localhost bin]# bash
[root@localhost bin]# echo $name

[root@localhost bin]# exit
exit
只读变量和本地变量一样只能在当前shell生效,要想在子shell生效需要执行export变为环境变量
位置变量:在脚本代码中调用通过命令行传递给脚本的参数

$1、$2.........${10}.........:在脚本中调用传递给脚本的对应参数,注意:两位数以上的数要加括号
$0表示脚本本身,如果执行脚本时写的全路径,$0就表示全路径加脚本名
$*传递给脚本的所有参数,如果被引号括起来则是一个字符串
$@和$*一样,但它叫所有参数看作不同的字符串
$#:传递给脚本的参数个数
$$:当前进程的pid
[root@localhost bin]# cat teshu.sh
#!/bin/bash
./teshu1.sh "$*"
echo "-------------------------"
./teshu1.sh "$@"
echo "-------------------------"
./teshu1.sh $*
echo "-------------------------"
./teshu1.sh $@
echo "-------------------------"
[root@localhost bin]# cat teshu1.sh
#!/bin/bash
echo "the first arg is $1"
echo "the first arg is $2"
echo "the first arg is $3"
echo "the num agrs is: $#"
[root@localhost bin]# bash teshu.sh abc 123 hello
the first arg is abc 123 hello
the first arg is
the first arg is
the num agrs is: 1
-------------------------
the first arg is abc
the first arg is 123
the first arg is hello
the num agrs is: 3
-------------------------
the first arg is abc
the first arg is 123
the first arg is hello
the num agrs is: 3
-------------------------
the first arg is abc
the first arg is 123
the first arg is hello
the num agrs is: 3
-------------------------
[root@localhost bin]#


二、算数运算
bash中的算数运算有:+、-、*、/、%、**等
实现算数运算:
1、let var=算数表达式
[root@localhost bin]# let a=1+2
[root@localhost bin]# echo $a
3
2、var=$[算数表达式]

[root@localhost bin]# a=1
[root@localhost bin]# b=2
[root@localhost bin]# c=$[a+b]
[root@localhost bin]# echo $c
3
3、var=$((算术表达式))
[root@localhost bin]# c=0
[root@localhost bin]# c=$((a+b))
[root@localhost bin]# echo $c
3
4、var=$(expr arg1 op arg2):算数操作符两边必须空格
[root@localhost bin]# a=2
[root@localhost bin]# b=2
[root@localhost bin]# c=`expr $a \* $b`
[root@localhost bin]# echo $c
4
[root@localhost bin]# c=`expr $a * $b`
expr: syntax error
5、echo "算是表达式" |bc 能够支持小数运算

三、聚合命令
有两种聚集命令的方式:
1、复合式
[root@localhost bin]# date;who |wc -l
Sat Aug 13 11:07:13 CST 2016
2
[root@localhost bin]#
以分号为分隔符,依次来执行命令,命令之间没有逻辑关系
2、子shell式
[root@localhost bin]# (sleep 20 && ls /etc)|wc -l
270




当执行上面的命令时,括号生成一个新的bash,wc将等待子shell的结果

四、退出状态码

Linux中退出状态码来判断进程是否执行成功,$?代表上一个进程的退出状态码,其中0代表成功,1-255代表失败

自定义退出码:exit
在脚本中有时我们通过判断了解到当前环境不适合继续执行该脚本,则可使用exit退出,默认退出码是0

五、条件测试
判断某需求是否满足,需要由测试机制来实现
测试命令:

1、test expression一般很少用
2、[ expression ]中括号里的expression两边必须加空格,一般由于数值判断和文件判断
3、` expression `expression两边必须加空格,一般用于字符串的判断
数值测试:

-gt: 是否大于;
-ge: 是否大于等于;
-eq: 是否等于;
-ne: 是否不等于;
-lt: 是否小于;
-le: 是否小于等于;
数值测试比较大小不能用>、<等

字符串测试:

==:是否等于;
>:ascii码是否大于ascii码
<:是否小于
!=:是否不等于
=~:左侧字符串是否能够被右侧的PATTERN所匹配,支持。注意:右侧正则表达式为扩展正则,但是不支持单词锚定
-z:""STRING":字符串是否为空,空为真,不空为假
-n :"STRING":字符串是否不空,不空为真,空为假
注意:用于字符串比较时的用到的操作数都应该使用引号
文件测试

存在性测试:
-a FILE:同-e
-e FILE: 文件存在性测试,存在为真,否则为假;
存在性及类别测试
-b FILE:是否存在且为块设备文件;
-c FILE:是否存在且为字符设备文件;
-d FILE:是否存在且为目录文件;
-f FILE:是否存在且为普通文件;
-h FILE 或-L FILE:存在且为符号链接文件;
-p FILE:是否存在且为命名管道文件;
-S FILE:是否存在且为套接字文件;
注意:如果要判断符号链接文件,应放在-f和-d的前面。
文件权限测试:
-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行
注意:此处判断的是当前登录用户的权限,且判断时要注意该文件所在的目录是否有执行权限
文件特殊权限测试:
-g FILE:是否存在且拥有sgid权限;
-u FILE:是否存在且拥有suid权限;
-k FILE:是否存在且拥有sticky权限;
文件大小测试:
-s FILE: 是否存在且非空;

文件是否打开:
-t fd: fd表示文件描述符是否已经打开且与某终端相关
-N FILE:文件自动上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组
双目测试:
FILE1 -ef FILE2: FILE1与FILE2是否指向同一个设备上的相同inode
FILE1 -nt FILE2: FILE1是否新于FILE2;

FILE1 -ot FILE2: FILE1是否旧于FILE2;

六、接受用户输出:
使用read来把输入值分配给一个或多个shell变量:
-p:指定要显示的提示

-t:timeout指定等待超时时间
read 从标准输入中读取值,给每个单词分配一个变量所有剩余单词都被分配给最后一个变量

七、练习:
1、编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小。

[root@localhost bin]# bash systeminfo.sh
Hostname: localhost.localdomain
IP address: 10.1.70.102
System version: CentOS Linux release 7.2.1511 (Core)
Kernel release: 3.10.0-327.el7.x86_64
CPU type: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
Memory size: 1.8G
Disk size: 200G
[root@localhost bin]# cat systeminfo.sh
#!/bin/bash
hostname=`hostname`
ipaddr=`ifconfig |sed -nr '2s/^[^[:digit:]]+([0-9.]+\b).*/\1/p'`
system=`cat /etc/centos-release`
kernel=`uname -r`
cpu=`grep "model name" /proc/cpuinfo |head -1|cut -c14-54`
mem=`free -h|grep "Mem"|tr -s ' '|cut -d ' ' -f2`
disk=`lsblk|grep -w "sda"|tr -s ' '|cut -d ' ' -f4`
echo -e "Hostname: \033[33m$hostname\033[0m"
echo -e "IP address: \033[33m$ipaddr\033[0m"
echo -e "System version: \033[33m$system\033[0m"
echo -e "Kernel release: \033[33m$kernel\033[0m"
echo -e "CPU type: \033[33m$cpu\033[0m"
echo -e "Memory size: \033[33m$mem\033[0m"
echo -e "Disk size: \033[33m$disk\033[0m"
unset hostname ipaddr system kernel cpu mem disk
2、编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到/root/etcYYYY-mm-dd中
[root@localhost bin]# bash backup.sh
copying
[root@localhost bin]# echo $?
0
[root@localhost bin]# bash backup.sh
copying has been done today
[root@localhost bin]# echo $?
1
[root@localhost bin]# cat backup.sh
#!/bin/bash
date=`date +%F`
[ -e /root/etc${date} ] &&  echo "copying has been done today" && exit 1 || echo "copying" && cp -r /etc /root/etc${date}
3、编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利用率最大的值
[root@localhost bin]# bash disk.sh
The maximum value of disk utilization is:38%
[root@localhost bin]# cat disk.sh
#!/bin/bash
rate=`df|tr -s ' '|grep -oE "\b[0-9]{1,3}%"|sort -nr|head -1`
echo "The maximum value of disk utilization is:$rate"
unset rate
4、编写脚本/root/bin/links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序
[root@localhost bin]# bash links.sh
the link num is:
2 10.1.250.91
[root@localhost bin]# cat links.sh
#!/bin/bash
echo -e "the link num is:\n `netstat -nt|tr -s ' '|cut -d ' ' -f5|grep -o "^[0-9.]\+\b"|sort|uniq -c|sort -nr`"
5、写一个脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的ID之和
[root@localhost bin]# bash sumid.sh
the sum of uid is: 184
[root@localhost bin]# cat sumid.sh
#!/bin/bash
ten=`sed -n '10p' /etc/passwd|cut -d: -f3`
twe=`sed -n '20p' /etc/passwd|cut -d: -f3`
echo "the sum of uid is: $((twe+ten))"
unset ten twe
6、写一个脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和
[root@localhost bin]# bash sumspace.sh /etc/profile /etc/issue /usr/bin/echo
The /etc/profile has spaceline: 11
The /etc/issue has spaceline: 1
The /usr/bin/echo has spaceline: 1
The total spaceline is:13
[root@localhost bin]# cat sumspace.sh
#!/bin/bash
count=0
for i in `seq 1 $#`
do
if [ ! -f $1 ];then
echo "Please type right name of file $1"
else
num=`grep "^[[:space:]]*$" $1|wc -l`
echo "The $1 has spaceline: $num"
let count=$count+$num
fi
shift
done
echo "The total spaceline is:$count"
unset count num
7、写一个脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件
[root@localhost bin]# bash sumfile.sh /etc/ /var/ /usr/
the /etc/ has file 270
the /var/ has file 21
the /usr/ has file 12
Total num of file is 303
[root@localhost bin]# bash sumfile.sh
Total num of file is 0
[root@localhost bin]# bash sumfile.sh /etc
please enter dir name like /etc/
Total num of file is 0
[root@localhost bin]# bash sumfile.sh /etc/ /var/ /usr/
the /etc/ has file 270
^[[3~the /var/ has file 21
the /usr/ has file 12
Total num of file is 303
[root@localhost bin]# bash sumfile.sh /etc/ /var/ /usr/ /var/ /bin/ /usr/bin/
the /etc/ has file 270
the /var/ has file 21
the /usr/ has file 12
the /var/ has file 21
the /bin/ has file 1923
the /usr/bin/ has file 1923
Total num of file is 4170
[root@localhost bin]# cat sumfile.sh
#!/bin/bash
count=0
for i in `seq 1 $#`
do
if [[ ! $1 =~ .*/$ ]];then
echo "please enter dir name like /etc/"
elif [ ! -d $1 ];then
echo "$1 does not exsit"
else
dir=`echo "$1"|sed -r 's@.*@&*@'`
num=`ls -d $dir|wc -l`
echo "the $1 has file $num"
let count=$count+$num
fi
shift
done
echo "Total num of file is $count"
unset count dir num
[root@localhost bin]#
8、写一个脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数
[root@localhost bin]# bash argsnum.sh
Please type filename:/etc/profile
The firstfile has spaceline 11
[root@localhost bin]# bash argsnum.sh
Please type filename:/etc/issue
The firstfile has spaceline 1
[root@localhost bin]# bash argsnum.sh
Please type filename:
One file should be input at least
[root@localhost bin]# bash argsnum.sh
Please type filename:/etc
The firstarg is not a file
[root@localhost bin]# cat argsnum.sh
#!/bin/bash
read -p "Please type filename:" file
if [[ -z $file ]];then
echo "One file should be input at least"
exit 1
else
firstfile=`echo $file|cut -d ' ' -f1`
if [[ ! -f $firstfile ]];then
echo "The firstarg is not a file"
exit 2
else
num=`grep -E "^[[:space:]]*$" $firstfile|wc -l`
echo "The firstfile has spaceline $num"
fi
fi
unset file firstfile num
9、写一个脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”
[root@localhost bin]# bash hostping.sh
Please type ipaddr:10.1.0l.1
ping failture
[root@localhost bin]# bash hostping.sh
Please type ipaddr:10.0.0.1
ping failture
[root@localhost bin]# bash hostping.sh
Please type ipaddr:10.1.0.1
ping successfull
[root@localhost bin]# cat hostping.sh
#!/bin/bash
read -p "Please type ipaddr:" ip
ping -c1 -W1 $ip &> /dev/null && echo ping successfull || echo  ping failture
10、判断硬盘的每个分区空间和inode的利用率是否大于80,如果是,发邮件通知root磁盘满
[root@localhost bin]# cat diskwarnning.sh
#!/bin/bash
while true;do
rate=`(df ;df -i )|tr -s ' '|cut -d ' ' -f5|grep -oE "\b[0-9]{1,3}\b"|sort -nr|head -1`
if [ $rate -gt 80 ];then
echo "The disk will be filled"|mail -s warnning root && break
else
echo "The disk is enough to use,maximum utilization is ${rate}%"
fi
sleep 1
done
unset rate
while true;do
echo "Mail has been sent,please to check"
sleep 1
done
[root@localhost bin]# bash diskwarnning.sh
The disk is enough to use,maximum utilization is 38%
The disk is enough to use,maximum utilization is 38%
The disk is enough to use,maximum utilization is 38%
The disk is enough to use,maximum utilization is 38%
The disk is enough to use,maximum utilization is 38%
.........
[root@localhost testdir]# dd if=/dev/zero of=zero bs=1G count=17



可以看到,磁盘最大利用率一直在增大,当大于80%时就发送报警邮件
[root@localhost bin]# mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/root": 5 messages 5 new
>N  1 root                  Tue Aug 16 09:13  18/626   "warnning"
N  2 root                  Tue Aug 16 09:13  18/626   "warnning"
[root@localhost testdir]# df
Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/sda2       51175000  4320900  46854100   9% /
devtmpfs          919820        0    919820   0% /dev
tmpfs             934344        0    934344   0% /dev/shm
tmpfs             934344     9112    925232   1% /run
tmpfs             934344        0    934344   0% /sys/fs/cgroup
/dev/sda5       20469760 17858788   2610972  88% /testdir
/dev/sda1         406188   151904    254284  38% /boot
tmpfs             186872        0    186872   0% /run/user/0
You have mail in /var/spool/mail/root
11、指定文件做为参数,判断文件是否为.sh后缀,如果是,添加x权限
[root@localhost bin]# ll
total 68
-rw-r--r--. 1 root root  24 Aug 13 18:07 a
-rw-r--r--. 1 root root 372 Aug 13 17:12 argsnum.sh
-rw-r--r--. 1 root root 151 Aug 13 15:41 backup.sh
-rw-r--r--. 1 root root 140 Aug 13 15:55 disk.sh
-rw-r--r--. 1 root root 377 Aug 16 09:15 diskwarnning.sh
-rw-r--r--. 1 root root 123 Aug 13 17:17 hostping.sh
-rwxr-xr-x. 1 root root   0 Aug 13 11:12 juji.sh
-rwxr-xr-x. 1 root root 124 Aug 13 16:02 links.sh
-rw-r--r--. 1 root root 262 Aug 16 09:36 privilege.sh
-rw-r--r--. 1 root root 355 Aug 13 16:42 sumfile.sh
-rw-r--r--. 1 root root 151 Aug 13 16:07 sumid.sh
-rwxr-xr-x. 1 root root 281 Aug 13 16:23 sumspace.sh
-rwxr-xr-x. 1 root root 671 Aug 13 15:33 systeminfo.sh
-rwxr-xr-x. 1 root root 120 Aug 13 10:51 teshu1.sh
-rwxr-xr-x. 1 root root 209 Aug 13 10:50 teshu.sh
-rwxr-xr-x. 1 root root  34 Aug 13 10:06 testenv2.sh
-rw-r--r--. 1 root root  96 Aug 13 10:07 testenv.sh
-rwxr-xr-x. 1 root root   1 Aug 13 18:25 warnning.sh
[root@localhost bin]# bash privilege.sh a argsnum.sh backup.sh disk.sh diskwarnning.sh hostping.sh privilege.sh sumfile.sh sumid.sh /etc/init.d/functions /var/log/secure
The file a is not a script file!
Execute permission of argsnum.sh has been added
Execute permission of backup.sh has been added
Execute permission of disk.sh has been added
Execute permission of diskwarnning.sh has been added
Execute permission of hostping.sh has been added
Execute permission of privilege.sh has been added
Execute permission of sumfile.sh has been added
Execute permission of sumid.sh has been added
The file /etc/init.d/functions is not a script file!
The file /var/log/secure is not a script file!
[root@localhost bin]# ll a argsnum.sh backup.sh disk.sh diskwarnning.sh hostping.sh privilege.sh sumfile.sh sumid.sh /etc/init.d/functions /var/log/secure
-rw-r--r--. 1 root root    24 Aug 13 18:07 a
-rwxr-xr-x. 1 root root   372 Aug 13 17:12 argsnum.sh
-rwxr-xr-x. 1 root root   151 Aug 13 15:41 backup.sh
-rwxr-xr-x. 1 root root   140 Aug 13 15:55 disk.sh
-rwxr-xr-x. 1 root root   377 Aug 16 09:15 diskwarnning.sh
-rw-r--r--. 1 root root 13948 Sep 16  2015 /etc/init.d/functions
-rwxr-xr-x. 1 root root   123 Aug 13 17:17 hostping.sh
-rwxr-xr-x. 1 root root   262 Aug 16 09:36 privilege.sh
-rwxr-xr-x. 1 root root   355 Aug 13 16:42 sumfile.sh
-rwxr-xr-x. 1 root root   151 Aug 13 16:07 sumid.sh
-rw-------. 1 root root   711 Aug 16 08:51 /var/log/secure
[root@localhost bin]#
12、判断输入的IP是否为合法IP
[root@localhost bin]# cat ipcheck.sh
#!/bin/bash
read -p "Please enter the ipaddr:" ip
echo $ip | grep -E "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>$" &> /dev/null  && echo "this is a useful ip" || echo "this is not useful ip"
[root@localhost bin]# bash ipcheck.sh
Please enter the ipaddr:10.10.10.10
this is a useful ip
[root@localhost bin]# bash ipcheck.sh
Please enter the ipaddr:10.10.10.10.
this is not useful ip
[root@localhost bin]# bash ipcheck.sh
Please enter the ipaddr:10.10.1.256
this is not useful ip
13、计算1+2+3+...+100
[root@localhost bin]# bash sumand.sh
Please enter a int that is great then one:55
1540
[root@localhost bin]# bash sumand.sh
Please enter a int that is great then one:100
5050
[root@localhost bin]# cat sumand.sh
#!/bin/bash
read -p "Please enter a int that is great then one:" int
echo `seq 1 $int`|tr ' ' '+'|bc
14、输入起始值A和最后值B,计算从A+(A+1)...+(B-1)+B的总和
[root@localhost bin]# bash sumrandom.sh
Please enter the first num:10
please enter the second num:15
75
[root@localhost bin]# bash sumrandom.sh
Please enter the first num:15
please enter the second num:10
75
[root@localhost bin]# cat sumrandom.sh
#!/bin/bash
read -p "Please enter the first num:" first
read -p "please enter the second num:" second
[ $first -gt $second ] && echo `seq $second $first`|tr ' ' '+'|bc || echo `seq $first $second`|tr ' ' '+'|bc
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux shell 变量