Shell 基础之变量和条件判断
一、shell概述
1、shell概述:
shell是一个命令行的解释器,为用户提供了一个向Linux内核发送请求以便运行程序的界面系统及程序,用户可以用shell来启动、挂起、停止甚至编写一些程序,shell还是一个功能强大的编程语言,shell是解释性的脚本语言,在shell中可以直接调用Linux命令。
2、shell脚本的用途
(1)自动化常用的命令
(2)执行系统管理和故障排除
(3)执行简单的应用程序
(4)处理文本或文件
3、shell的分类
(1)Bourne shell:从1979起unix开始使用,Bourne shell 的主文件名为sh
(2)c shell:主要在BSD版的Unix系统中使用,其语法和c语言相似
(3)shell的两种主要语法类型有Bourne和c,这两种语法不兼容。Bourne家族主要包括sh,ksh,bash,psh,zsh;c家族主要包括csh、tcsh
(4)Bash:Bash与sh兼容,现在使用的linux就是使用Bash作为用户的基本shell
二、shell脚本的开发基础及使用习惯
1、shell脚本的使用习惯
(1)第一行必须包括shell声明序列(指定脚本的解释器)如:
#!/bin/bash
(2)开头加版本版权信息如:
#!/bin/bash
#Author: wang
#Version: 1.0
#mail:[email protected]
#Date: 2016-05-01
#Description:The script displays system information
(3)脚本不用中文注释
(4)脚本以.sh为扩展名
(5)代码书写优秀习惯
2、脚本执行
(1)脚本的执行方式:
1)给予执行权限,在命令行上指定脚本的绝对或相对路径
2)直接运行解释器,将脚本作为解释器程序的参数运行
(2)脚本调试
1)检测脚本中的语法错误
bash -n /home/dayi123/dayi123.sh
2)调试执行
bash -x /home/dayi123/dayi123.sh
3、echo命令的输出
(1)输出语法:echo [选项] 输出内容
(2)选项:-e 支持反斜杠控制的字符转码
\\ 输出命令本身
\a 输出警告声
\b 退格键,即向左删除键
\c 取消输出行尾的换行符
\e ESPCAPE键
\f 换页符
\n 换行符
\r 回车键
\t 指标符
\v 垂直制表符
\0nnn 按照八进制ASCII码表输出字符(0为数字,nnn为八进制数)
\xhh 按照十六进制ASCII码表输出字符,hh为两位十六进制数
(3)echo输出与颜色
1)字体颜色
echo -e “\033[30m 黑色字 \033[0m”?
31m 红色字 32m 绿色字 33m 黄色字 34m 蓝色字
35m 紫色字 36m 天蓝字 37m 白色字
2)背景颜色
echo -e “\033[40;37m 黑底白字 \033[0m”?
echo -e “\033[41;37m 红底白字 \033[0m”?
echo -e “\033[42;37m 绿底白字 \033[0m”?
echo -e “\033[43;37m 黄底白字 \033[0m”?
echo -e “\033[44;37m 蓝底白字 \033[0m”?
echo -e “\033[45;37m 紫底白字 \033[0m”?
echo -e “\033[46;37m 天蓝底白字 \033[0m”?
echo -e “\033[47;30m 白底黑字 \033[0m”
三、变量
1、变量的概述
(1)概述:变量是计算机内存的单元,其中存放的值可以改变,当shell脚本需要保存一些信息时,如一个文件名或是一个数字,就把他存放在一个变量中,每个变量有一个名字,所以很容易引用它。
(2)变量的类型:
1)强类型:变量不经过强制转换,它永远是这个数据类型,不允许隐式的类型转换。一般定义变量时必须指定类型、参与运算必须符合类型要求;调用未声明变量会产生错误。
2)弱类型:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用。
(3)变量的命名规则:
1)变量名称可由字母、数字、下划线组成、但不能以数字开头
2)Bash中,变量的类型都是字符串性,如果要进行数值运算,则必须指定变量类型为数值型。
3)变量要用等号连接,等号两侧不能有空格。
4)变量的值如果有空格,需要使用单引号或双引号包括。
5)在变量的值中可以使用“\”转义字符
6)如果要增加变量的值,变量的值可以进行叠加,不过变量的值需要使用双引号“$变量名”或${变量名}包含
7)如果将命令的结果作为值赋予变量,则需要使用反引号或$()包含命令。
8)环境变量名大写,便于区分
2、变量的种类
(1)本地变量(用户自定义变量)
1)变量的定义:name=”value”
2)变量的引用:
a、可以是直接字串; name=“root"
b、变量引用:name="$USER"
c、命令引用:name=`COMMAND` name=$(COMMAND)
[[email protected] ~]# name=dayi123 #定义一个变量
[[email protected] ~]# echo $name #输出变量
dayi123
[[email protected] ~]# name=`date` #变量引用命令
[[email protected] ~]# echo "$name" #弱引用,其中的变量引用会被替换为变量值
2017年 04月 10日星期一 20:18:42 CST
#强引用,其中的变量引用不会被替换为变量值,而保持原字符串
[[email protected] ~]# echo ‘$name‘
$name
3)变量的查看:set
4)删除变量:unset name
5)变量的叠加:
[[email protected] ~]# name=dayi123
[[email protected] ~]# echo $name
dayi123
[[email protected] ~]# aa=${name}nb
[[email protected] ~]# echo $aa
dayi123nb
(2)环境变量
1)概述:用户自定义变量只在当前的shell中生效,而环境变量会在当前的shell和这个shell的所有子shell当中生效。如果把环境变量写入相应的配置文件,那么这个环境变量会在所有的shell中生效。
2)环境变量的设置与查看:
设置:export name=VALUE
Declare –x name=VALUE
查看:env
printenv
export
declare –x
删除:unset name
[[email protected] ~]# export name="dayi123" #设置环境变量
[[email protected] ~]# env | grep name #查看环境变量
name=dayi123
[[email protected] ~]# printenv | grep name
name=dayi123
[[email protected] ~]# declare -x | grep name
declare -x name="dayi123"
[[email protected] ~]# unset name #删除环境变量
[[email protected] ~]# declare -x | grep name
[[email protected] ~]#
3)系统常见的环境变量::PATH, SHELL, USRE,UID,HISTSIZE, HOME, PWD, OLDPWD, HISTFILE
PATH:系统查找命令的路径
PATH变量叠加:PATH=”$PATH”:/root/dayi123
[[email protected] ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[[email protected] ~]# PATH="$PATH":/root/dayi132
[[email protected] ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/dayi132
(3)只读变量:只能声明,但不能修改和删除
1)声明只读变量:
readonly name
declare -r name
2)查看只读变量:
readonly –p
(4)位置变量(位置参数变量):在脚本代码中调用通过命令行传递给脚本的参数
1)$1, $2, ...:对应第1、第2等参数,shift [n]换位置
2)$0: 命令本身
3)$*: 传递给脚本的所有参数,全部参数合为一个字符串
4)[email protected]: 传递给脚本的所有参数,每个参数为独立字符串
5)$#: 传递给脚本的参数的个数
6)[email protected] $* 只在被双引号包起来的时候才会有差异
7)set -- 清空所有位置变量
[[email protected] dayi123]# cat parameters.sh
#!/bin/bash
echo -e "==================begin================="
echo -e "firest parameters:\033[33m $1 \033[0m" #打印接受的第一个参数
echo -e "totle paramerers:\033[33m $# \033[0m" #打印接受参数的个数
echo -e "the paramerers is:\033[33m $* \033[0m" #把所有参数当做一个整体打印
echo -e "the parameters is:\033[31m [email protected] \033[0m" #打印所有参数,但会区分对待
echo -e "==================end==================="
[[email protected] dayi123]# sh parameters.sh 12 dayi dashen boy
==================begin=================
firest parameters: 12
totle paramerers: 4
the paramerers is: 12 dayi dashen boy
the parameters is: 12 dayi dashen boy
==================end===================
[[email protected] dayi123]#
三、变量的运算
1、算术运算:
(1)运算符:+,-, *(有些场景需要转义),/,%取模(取余),**(乘方)
(2)实现方法:
1)let var=算术表达式
[[email protected] dayi123]# let num=10+10
[[email protected] dayi123]# echo $num
20
2)var=$[算术表达式]
[[email protected] dayi123]# var=$[10+10*2]
[[email protected] dayi123]# echo $var
30
3)var=$((算术表达式))
[[email protected] dayi123]# var=$[10+10/2]
[[email protected] dayi123]# echo $var
15
4)var=$(expr arg1 arg2 arg3 ...)
[[email protected] ~]# var=$(expr 23 + 20)
[[email protected] ~]# echo $var
43 [[email protected] ~]# expr 2 + 2
4
[[email protected] ~]# expr 2 \* 200 #乘法要转义
400
[[email protected] ~]# expr 67 % 30 #取模
7
5)declare –i var = 数值
[[email protected] ~]# declare -i var=10*10
[[email protected] ~]# echo $var
100
6)echo ‘算术表达式’ | bc
[[email protected] ~]# echo {1..100} | tr " " "+" | bc
5050
2、赋值运算
(1)赋值符号:+=, -=, *=, /=, %=
(2)应用:
[[email protected] ~]# let num++
[[email protected] ~]# echo $num
2
[[email protected] ~]# let num-=2
[[email protected] ~]# echo $num
0
3、逻辑运算
(1)true(1), false(0)
(2)与: 1 与 1 = 1(对与对为对)
1 与 0 = 0(对与错 为错)
0 与 1 = 0(错与对 为错)
0 与 0 = 0(错与错 为对)
(3)或: 1 或 1 = 1(对或对 为对)
1 或 0 = 1(对或对 为对)
0 或 1 = 1(错或对 为对)
0 或 0 = 0(错或错 为错)
(4)非:!
! 1 = 0(非对为错)
! 0 = 1(非错为对)
(5)短路运算:
短语与:第一个为0,结果必定为0
第一个为1,第二个必须要参与运算
短路或:
第一个为1,结果必定为1
第一个为0,第二个必须要参与运算
异或:^
异或的两个值,相同为假,不同为真
4、退出状态
(1)进程使用退出状态来报告成功或失败
0 代表成功,1-255代表失败
$? 变量保存最近的命令退出状态(即程序的执行结果)
(2)bash自定义退出状态码
exit [n]:自定义退出状态码
1):脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
2):如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
[[email protected] ~]# pwd
/root
[[email protected] ~]# echo $? #命令执行成功,返回0
0
[[email protected] ~]# lsd
bash: lsd: 未找到命令... #执行失败,返会非0(1-255)
[[email protected] ~]# echo $?
127
四、条件判断
1、条件测试
(1)作用:判断某需求是否满足,需要由测试机制来实现专用的测试表达式需要由测试命令辅助完成测试过程
(2)评估布尔声明,以便用在条件性执行中
若真,则返回0
若假,则返回1
(3)测试命令:
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
注意:EXPRESSION前后必须有空白字符
(4)根据退出状态而定,命令可以有条件地运行
&& 代表条件性的AND
|| 代表条件性的OR
[[email protected] ~]# ls || date #如果前面命令执行成功,则后面的不执行
1.sh anaconda-ks.cfg dayi.txt initial-setup-ks.cfg 模板 图片 下载 桌面
2.sh dayi123 EOF 公共 视频 文档 音乐
[[email protected] ~]# ls && date #如果前面的命令执行成功,后面的命令才会执行
1.sh anaconda-ks.cfg dayi.txt initial-setup-ks.cfg 模板 图片 下载 桌面
2.sh dayi123 EOF 公共 视频 文档 音乐
2017年 04月 10日星期一 22:06:20 CST
2、数值比较:
判断式 |
作用 |
实例 |
示例说明 |
-eq |
相等 |
[ 23 –eq 22 ] && ehco “yes” || echo “NO” |
判断23和22是否相等 |
-ne |
不相等 |
[ 23 –ne 22 ] && ehco “yes” || echo “NO” |
判断23和22是否不相等 |
-gt |
大于 |
[ 23 –gt 22 ] && ehco “yes” || echo “NO” |
判断23是否大于22 |
-lt |
小于 |
[ 23 –lt 22 ] && ehco “yes” || echo “NO” |
判断23是否小于22 |
-ge |
大于等于 |
[ 23 –ge 22 ] && ehco “yes” || echo “NO” |
判断23是否大于等于22 |
-le |
小于等于 |
[ 23 –le 22 ] && ehco “yes” || echo “NO” |
判断23是否小于等于22 |
3、字符串的判断
判断式 |
说明 |
-z “string” |
判断字符串是否为空(为空返回真) |
-n “string” |
判断字符串是否为非空(非空返回真) |
“string”==”string2” |
判断字符串1是否和字符串2相等(相等返回真) |
“string1”!=”string2” |
判断字符串1是否和字符串2不相等(不相等返回真) |
“string1”=~”string2” |
判断左侧字符串是否能够被右侧的PATTERN所匹配 |
> |
ascii码是否大于ascii码 |
< |
ascii码是否小于ascii码 |
[[email protected] ~]# [[ "hostname" =~ "host" ]] && echo "OK"
OK
[[email protected] ~]# BJ=Beijing
[[email protected] ~]# [[ -z "$BJ" ]] && echo "null" || echo "not null"
not null
[[email protected] ~]# [[ "liuy" == "dayi123" ]] && echo "OK" || echo "NO"
NO
4、按照文件的存在性以及类型判断
判断式 |
说明 |
-b 文件 |
判断该文件是否存在,并且是否为快设备文件 |
-c 文件 |
判断该文件是否存在,并且是否为字段设备文件(时字符设备文件为真) |
-d 文件 |
判断该文件是否存在,并且是否为目录文件(为目录文件为真) |
-e 文件 |
判断该文件是否存在(存在为真) |
-f 文件 |
判断该文件是否存在,并且是否为普通文件(是普通文件为真) |
-L 文件 |
判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真) |
-p 文件 |
判断该文件是否存在,并且是否为管道文件(是管道文件为真) |
-s 文件 |
判断该文件是否存在,并且是否为非空(为非空为真) |
-S 文件 |
判断该文件是否存在,并且是否为套接字文件(是套接字文件为真) |
[[email protected] ~]# [[ -f /etc/profile ]] && echo "OK" || echo "not OK"
OK
[[email protected] ~]# [[ -d /etc/ ]] && echo "OK" || echo "not OK"
OK
[[email protected] ~]# [[ -e /home/dayi123 ]] && echo "OK" || echo "not OK"
OK
5、根据文件权限进行判断
判断式 |
说明 |
-r 文件 |
判断该文件是否存在,并且该文件是否拥有读权限(有读权限为真) |
-w 文件 |
判断该文件是否存在,并且该文件是否拥有写权限(有写权限为真) |
-x 文件 |
判断该文件是否存在,并且该文件是否拥有执行权限(有执行权限为真) |
-u 文件 |
判断该文件是否存在,并且该文件是否拥有suid权限(有suid权限为真) |
-g 文件 |
判断该文件是否存在,并且该文件是否拥有sgid权限(有sgid权限为真) |
-k 文件 |
判断该文件是否存在,并且该文件是否拥有sbit权限(有sbit权限为真) |
[[email protected] ~]# [ -w dayi.txt ] && echo "yes" || echo "NO"
yes
[[email protected] ~]# [ -x dayi.txt ] && echo "yes" || echo "NO"
NO
[[email protected] ~]# [ -u dayi.txt ] && echo "yes" || echo "NO"
NO
[[email protected] ~]# chmod 4755 dayi.txt
[[email protected] ~]# [ -u dayi.txt ] && echo "yes" || echo "NO"
yes
6、两个文件之间进行比较
判断式 |
说明 |
File1 –nt file2 |
判断文件1的修改时间是否比文件2新(如果新则为真) |
File1 –ot file2 |
判断文件1的修改时间是否比文件2旧(如果旧则为真) |
File1 –ef file2 |
判断文件1的inode号和文件2的inode号一致 |
[[email protected] ~]# [ dayi.txt -nt dayi123.log ] && echo "yes" || echo "no"
no
[[email protected] ~]# ll dayi*
-rw-r--r--. 1 root root 5 4月 10 23:27 dayi123.log
-rwsr-xr-x. 1 root root 0 4月 3 21:30 dayi.txt
[[email protected] ~]# [ /root/dayi.txt -ef /tmp/dayi123.txt ] && echo "yes" || echo "no"
Yes
[[email protected] ~]# ll -i /root/dayi.txt /tmp/dayi123.txt
70950384 -rwsr-xr-x. 2 root root 0 4月 3 21:30 /root/dayi.txt
70950384 -rwsr-xr-x. 2 root root 0 4月 3 21:30 /tmp/dayi123.txt
综合案例:
(1)编写脚本/root/script/sumid.sh,计算/etc/passwd文件中
的第10个用户和第20用户的ID之和
[[email protected] script]# cat sumid.sh
#!/bin/sh
ONEUSERID=`sed -n 10p /etc/passwd | cut -d":" -f3`
TWOUSERID=`sed -n 20p /etc/passwd | cut -d":" -f3`
let SUM=$ONEUSERID+$TWOUSERID
echo -e "two userid sum: \033[33m $SUM \033[0m"
[[email protected] script]# ./sumid.sh
two userid sum: 100
(2)编写脚本/root/scpipt/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和
[[email protected] script]# cat sumspace.sh
#!/bin/sh
[ $# -ne 2 ] && echo "pluse tow file" && exit 2
ONEFILE=`grep "^$" $1 | wc -l`
TWOFILE=`grep "^$" -c $2`
let SUM=$ONEFILE+$TWOFILE
echo -e "two file space sum: \033[33m $SUM \033[0m"
[[email protected] script]# sh sumspace.sh /etc/profile /etc/inittab
two file space sum: 11
(3)编写脚本/root/script/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件
[[email protected] script]# cat sumfile.sh
#!/bin/sh
ETC=`/bin/ls -l /etc/ | grep "^[-dlsp]" | wc -l`
VAR=`/bin/ls -l /var/ | grep "^[-dlsp]" | wc -l`
USR=`/bin/ls -l /usr/ | grep "^[-dlsp]" | wc -l`
let SUM=$ETC+$VAR+$USR
echo -e "totle: \033[33m $SUM \033[0m"
[[email protected] script]# sh sumfile.sh
totle: 210
(3)编写脚本/root/script/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数
[ -z "$1" ] && echo "please input your file or directory" && exit 2
FILE1=$1
SUM=$(cat $FILE1 | grep -i "^$" | wc -l)
echo -e "two file space sum: \033[33m $SUM \033[0m"
[[email protected] script]# sh argsnum.sh /etc/profile
two file space sum: 11
(5)编写脚本/root/script/hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”
[[email protected] script]# cat hostping.sh
#!/bin/sh
read -p "please input ipaddress:" IPADDRESS
echo "please wait......."
PING=`ping ${IPADDRESS} -c 4 | grep -o "\(received, \)[0-9]\{1,3\}%" | cut -d " " -f2`
[ $PING == 100% ] && echo "${IPADDRESS} unreachable" || echo "${IPADDRESS} to access"
[[email protected] script]# sh hostping.sh
please input ipaddress:172.16.250.102
please wait.......
172.16.250.102 to access
(6)编写脚本/root/bin/checkdisk.sh,检查磁盘分区空间和inode使用率,如果超过80%,就发广播警告空间将满
[[email protected] script]# cat hostping.sh
#!/bin/sh
read -p "please input ipaddress:" IPADDRESS
echo "please wait......."
PING=`ping ${IPADDRESS} -c 4 | grep -o "\(received, \)[0-9]\{1,3\}%" | cut -d " " -f2`
[ $PING == 100% ] && echo "${IPADDRESS} unreachable" || echo "${IPADDRESS} to access"
[[email protected] script]# sh hostping.sh
please input ipaddress:172.16.250.102
please wait.......
172.16.250.102 to access
(6)编写脚本/root/script/checkdisk.sh,检查磁盘分区空间和inode使用率,如果超过80%,就发广播警告空间将满
[[email protected] script]# cat checkdisk.sh
#!/bin/sh
DISK=`df -h | tr -s " " | cut -d" " -f1,5 | sort -nr -k2 | head -1 | cut -d" " -f1`
DISKNUM=`df -h | tr -s " " | cut -d" " -f1,5 | sort -nr -k2 | head -1 | cut -d" " -f2 | cut -d"%" -f1`
IDISK=`df -i | tr -s " " | cut -d" " -f1,5 | sort -nr -k2 | head -1 | cut -d" " -f1`
INUM=`df -i | tr -s " " | cut -d" " -f1,5 | sort -nr -k2 | head -1 | cut -d" " -f2 | cut -d"%" -f1`
[ $DISKNUM -ge 80 ] && echo -e "\033[31m $DISK lack of available space \033[0m" && wall "$DISK lack of available space" && exit
[ IDISK -ge 80 ] && echo -e "\033[31m $DISK lack of available space \033[0m" && wall "$DISK lack of available space" && exit
echo "disk normal"
[[email protected] script]# sh checkdisk.sh
/dev/sr0 lack of available space
[[email protected] script]#
Broadcast message from [email protected] (pts/0) (Fri Apr 7 23:52:28 2017):
/dev/sr0 lack of available space