第6章:变量、判断、循环、函数
6.1、变量
理念知识补充:
Shell变量如同传统的传统程序语言的变量一样,是用来保存某个值。在第1章入门已经有介绍过shell变量基本概念。
Shell脚本里经常会出现一些简单的运算,例如每经过一次循环,变量就会加1,POSIX标准的shell为内嵌算术提供了一些标记该当,称为算术展开。Shell会对 $((….)) 里的算术表达式进行计算,再将计算后的结果放回到命令的文本内容。
6.1.1、变量赋值与环境
有两个相似的命令提供变量的管理,一个是readonly,它可以使变量成为只读,而赋值给变量会被禁止。使用方法如下:
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
var1=1
var2=2
readonly var1 var2
另外一个常见的命令是export,其用法是将变量放进环境里,环境是一个名称与值的简单列表,可供所有执行中的程序使用,新的进程会从其父进程继承环境,也可以在建立新的子进程之前修改它。使用方法如下:
[root@cloucentos6 ~]# cat /home/test.sh #编写一个test.sh脚本显示本地回环IP地址
#!/bin/bash
ifconfig | grep "inet addr:127"
[root@cloucentos6 ~]# export -p | grep "PATH" #显示环境变量PATH
declare -x PATH="/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"
[root@cloucentos6 ~]# export PATH=$PATH:/home #临时添加环境变量PATH,系统重启后环境变量会消失,如果想永久生效可以把命令添加到/etc/profile文本
[root@cloucentos6 ~]# export -p | grep "PATH" #查看环境变量PATH是否添加成功
declare -x PATH="/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/home"
[root@cloucentos6 ~]# test.sh #直接运行脚本,无需输入完整路径
inet addr:127.0.0.1 Mask:255.0.0.0
标注:变量赋值常用有三种符号 双引号(" ")、单引号(' ')、反引号(` `)。
双引号(" ") 一般变量有空格或特殊字符进行使用,接受变量的赋值,例如:var="abc" echo "$var" 输出结果 abc;
单引号(' ') 一般变量有空格或特殊字符进行使用,不接受变量的赋值,例如:var='abc' echo '$var' 输出结果 $var;
反引号(` `) 允许你将shell命令输出赋给变量,例如:var=`arch` echo "$var" 输出结果 x86_64;
6.1.2、参数展开
参数展开是shell提供变量在程序中使用的过程,例如给新变量的值或作为命令的部分或全部参数。最简单的开形式如下所示:
var=”hello word!” #将值存储在var
sleep 120 #等待2分钟
echo $var #显示信息
在shell更复杂的形式可用于更特殊的情况,这些形式都是将变量名称括在花括号里(${var}) ,然后再增加额外的语法以告诉shell应该做些什么。当你需要在变量名称之后马上跟着一个可能会解释为名称的一部分的字符时,它就派上用户了。如下所示:
var=”hello word!” #将值存储在var
sleep 120 #等待2分钟
echo _${var}_ #显示信息,加下划线符号强调显示的信息
(1)、展开运算符
理论知识补充:
第一组字符串处理运算符用来测试变量的存在状态,且为某种情况下允许默认值替换。
范例1:替换运算符
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
var="hello word!"
echo ${var:-0} #如果var 存在并且非null,则返回其值;否则,返回0。用途:如果变量未定义,则返回默认值。
echo ${var:=0} #如果var 存在并且非null,则返回其值;否则,返回0并且返回其值。用途:如果变量未定义,则设置变量为默认值。
echo ${var:+word} #如果var 存在并且非null,则返回word;否则,null。用途:为测试变量的存在。
[root@cloucentos6 home]# ./test.sh
hello word!
hello word!
word
范例2:模式匹配运算符
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
var=/home/tolstoy/men/long.file.name.out
echo ${var#/*/} #模式匹配变量值开头处,则删除匹配开头部分,并返回剩下部分
echo ${var##/*/} #模式匹配变量值结尾处:,则删除匹配结尾部分,并返回剩下部分
echo ${var%.*} #模式匹配变量值开头处,则删除结尾最尾端的部分,并返回剩下部分
echo ${var%%.*} #模式匹配变量值结尾处,则返回最开头部分,并删除剩下部分
[root@cloucentos6 home]# ./test.sh
tolstoy/men/long.file.name.out
long.file.name.out
/home/tolstoy/men/long.file.name
/home/tolstoy/men/long
知识点补充1:
在这里用到的两种模式分别是 /*/ 匹配于任何位置两个斜杠之间的元素, . *匹配点号之后接着的任何元素。
知识点补充2:
POSIX标准化字符串长度运算符 ${#var} 返回$var变量值里的字符长度:
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
var=abc::
echo ${#var}
[root@cloucentos6 home]# ./test.sh
5
6.1.3、位置参数
理论知识补充:位置参数是从命令行传递给脚本,或者是传递给函数.或者赋职给一个变量。以下用范例说明位置参数的作用
范例1:$n指定显示参数
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
echo "命令本身:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "第三个参数:$3"
[root@cloucentos6 home]# ./test.sh a1 a2 a3
命令本身:./test.sh
第一个参数:a1
第二个参数:a2
第三个参数:a3
范例2:$*和$@显示全部参数
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
echo $*
echo $@
[root@cloucentos6 home]# ./test.sh a1 a2 a3
a1 a2 a3
a1 a2 a3
范例3:$#显示参数数量
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
echo $#
[root@cloucentos6 home]# ./test.sh a1 a2 a3
3
范例4:$*和$@位置参数区别
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
for i in "$*"
do
echo '$*' "显示:$i"
done
for i in "$@"
do
echo '$@' "显示:$i"
done
[root@cloucentos6 home]# ./test.sh a1 a2 a3
$* 显示:a1 a2 a3
$@ 显示:a1
$@ 显示:a2
$@ 显示:a3
范例5:用户输入shell默认会把空格当成分割两个值的分隔符,要在值中包含空格,必须使用引号(单引号或双引号均可)
[root@cloucentos6 home]# cat test.sh
#!/bin/bashecho $1echo $2[root@cloucentos6 home]# ./test.sh 1 212[root@cloucentos6 home]# ./test.sh '1 2' '34'
1 234[root@cloucentos6 home]# ./test.sh "1 2" "34"1 234
范例6:$0传递不是脚本名称,而是整个脚本路径,如果只想传递脚本名称得配合basename命令使用。
[root@cloucentos6 home]# cat test.sh
#!/bin/bashecho "Shell Script is : $0"[root@cloucentos6 home]# ./test.sh Shell Script is : ./test.sh[root@cloucentos6 home]# cat test.sh
#!/bin/bashname=`basename $0`echo "Shell Script is : $name"[root@cloucentos6 home]# ./test.sh Shell Script is : test.sh
6.1.4、内置变量
除了以上看过的特殊变量(例如$#及$*)之外,shell还有很多额外的内置shell变量。Shell内置变量好处在于你不用去赋值给这些变量,这些是系统已经定义好的变量,每个内置变量都有各自的功能。如下图所示:
范例:
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
echo $MACHTYPE
echo $SHELL
echo $HOME
[root@cloucentos6 home]# ./test.sh
x86_64-unknown-linux-gnu
/bin/bash
/root
6.2、算术运算符与运算表达式
理论知识补充:Shell的算术运行与C语言里的差不多,优先级与顺序也相同。表6-4列出支持的算术运算符,优先级由最高排列至最低,虽然有些是特殊字符,不过它们不需要以反斜杠转义,因为它们都置于$((…))语法中。这一语法如同双引号功能,除了内嵌双引号无须转义。算术运算符如下图所示:
运算表达式如下图所示:
范例1:运算表达式使用都置于$((…))或 $[…]语法
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
var1=$((1+3))
var2=$[1+3]
echo $var1
echo $var2
[root@cloucentos6 home]# ./test.sh
4
4
知识点2:|| 这个是逻辑或,只要两个表达式至少有一个为真即为1
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
echo $((3>2))
echo $(( (3<2) || (4>=1) ))
echo $(( (3>2) || (4>=1) ))
echo $((( 3<2) || (4<=1) ))
[root@cloucentos6 home]# ./test.sh
1
1
1
0
知识点3: 逻辑与 && 只要表达式有一个为假即为0,需要两个表达式都为真即为1
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
echo $(( (3<2) && (4>=1) ))
echo $(( (3>2) && (4>=1) ))
echo $((( 3<2) && (4<=1) ))
[root@cloucentos6 home]# ./test.sh
0
1
0
知识点4:对于 逻辑与和逻辑或运算符而言
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
echo $((3 && 4))
echo $((3 || 4))
echo $((0 && 4))
echo $((6 || 0))
[root@cloucentos6 home]# ./test.sh
1
1
0
1
范例1:+加法简写赋值形式
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
i=6
var=$((i+2))
echo $var
echo $((i+=2))
[root@cloucentos6 home]# ./test.sh
8
8
范例2:i++运算符,在结果产生前,先将变量返回,再执行加1操作;++i运算符,在结果产生前,先将变量加1,再返回新值给变量。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
i=6
echo $((i++)) $i
echo $((i--)) $i
echo $((++i)) $i
echo $((--i)) $i
[root@cloucentos6 home]# ./test.sh
6 7
7 6
7 7
6 6
6.3、if语句
If语句通过关系运算符判断表达式的真假来决定执行哪个分支。Shell有三种if判断语句。
在了解if条件判断语句前,先了解一下条件表达式、逻辑判断符、整数比较符、字符串比较符。
(1)、条件表达式
(2)、逻辑判断符
(3)、整数比较符
(4)、字符串比较符
6.3.1、if…fi语句
语法:
if [expression]
then
command
fi
讲解:
如果expression条件为true(真),执行then后面的command语句;如果返回false(假),将直接跳出if语句,不会执行任何语句。注意:expression和方括号 [ ] 之间必须有空格,否则会有语法错误。
范例:$1和$2传递参数进行比较,如果两个数字相等就输出等于,如果不相等就不执行任何语句。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
if [ $1 -eq $2 ]
then
echo "$1 等于 $2"
fi
[root@cloucentos6 home]# ./test.sh 1 2
[root@cloucentos6 home]# ./test.sh 2 2
2 等于 2
6.3.2、if…else…fi语句
If [ expression ]
then
command 1
else
command 2
fi
讲解:
如果expression返回true,那么执行then后边的command 1语句;否则,执行else后边的command 2语句。注意:expression和方括号 [ ] 之间必须有空格,否则会有语法错误。
范例:$1和$2传递参数进行比较,如果两个数字相等输出等于,如果不相等输出不等于。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
if [ $1 -eq $2 ]
then
echo "$1 等于 $2"
else
echo "$1 不等于 $2"
fi
[root@cloucentos6 home]# ./test.sh 2 2
2 等于 2
[root@cloucentos6 home]# ./test.sh 2 3
2 不等于 3
[root@cloucentos6 home]# ./test.sh 8 6
8 不等于 6
6.3.3、if…elif…else…fi语句
If [ expression 1 ]
then
command 1
elif [ expression 2]
then
command 2
elif [expression 3]
then
command 3
else
command 4
fi
讲解:
哪一个expression 的值为true就执行哪个expression后面的command语句,如果括号[ expreesion ]都为flase就执行else后面的command 4语句,如果所有都为false就不执行任何语句。
范例:1和$2传递参数进行比较,等于、大于或小于。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
if [ $1 -eq $2 ]
then
echo "$1 等于 $2"
elif [ $1 -gt $2 ]
then
echo "$1 大于 $2"
else
echo "$1 小于 $2"
fi
[root@cloucentos6 home]# ./test.sh 3 3
3 等于 3
[root@cloucentos6 home]# ./test.sh 10 9
10 大于 9
[root@cloucentos6 home]# ./test.sh 6 8
6 小于 8
6.4、case多选择语句
Case是一种多分枝选择结构语句。Case语句匹配一个值或一个模式,如果匹配成功,执行相匹配的命令。case语句格式如下:
case 值 in
模式 1)
command 1
;;
模式 2)
command 2
;;
模式 3)
command 3
;;
esac
范例:输入数字1到4,分别输出对应提示。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
echo "请输入数字 1 到 4"
read var
case $var in
1)
echo "你输入的数字是 1"
;;
2)
echo "你输入的数字是 2"
;;
3)
echo "你输入的数字是 3"
;;
4)
echo "你输入的数字是 4"
;;
esac
[root@cloucentos6 home]# ./test.sh
请输入数字 1 到 4
2
你输入的数字是 2
[root@cloucentos6 home]# ./test.sh
请输入数字 1 到 4
4
你输入的数字是 4
6.5、test文件测试
test命令可以处理shell脚本里的各类工作。它产生的不是一般的输出,而是可使用的退出状态。Test接受各种不同的参数,可控制它要执行哪一种测试。
范例1:测试两个字符串是否相等的两种表达式。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
if test "a" == "a"
then
echo "相等"
else
echo "不相等"
fi
if [ "a" == "b" ]
then
echo "相等"
else
echo "不相等"
fi
[root@cloucentos6 home]# ./test.sh
相等
不相等
范例2:判断/home目录下file.txt和abc.txt文件是否存在
[root@cloucentos6 home]# ls /home
file.txt lost+found test.sh
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
if [ -f "$1" ]
then
echo "$1 文件存在"
else
echo "$1 文件不存在"
fi
[root@cloucentos6 home]# ./test.sh /home/file.txt
/home/file.txt 文件存在
[root@cloucentos6 home]# ./test.sh /home/abc.txt
/home/abc.txt 文件不存在
范例3:逻辑判断符 –a 与 &&(逻辑与)功能一样, -o与 ||(逻辑或)功能一样。
[root@cloucentos6 home]# ls
file.txt font.txt lost+found test.sh
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
if [ -f "$1" -a -f "$2" ]
then
echo "$1文件存在,$2文件存在"
fi
if [ -f "$1" ] && [ -f "$2" ]
then
echo "$1文件存在,$2文件存在"
fi
[root@cloucentos6 home]# ./test.sh /home/file.txt /home/font.txt
/home/file.txt文件存在,/home/font.txt文件存在
/home/file.txt文件存在,/home/font.txt文件存在
[root@cloucentos6 home]# ./test.sh /home/file.txt /home/abc.txt
6.6、循环语句
Shell循环语句与C语言类似,不仅支持for循环语句也支持while与until循环语句。
6.6.1、for循环语句
与其C语言的for循环类似,shell也支持fot循环。for循环用于重复整个对象列表,依次执行每一个独立对象的循环内容。对象可能是命令行参数、文件名或是任何可以以列表格式建立的东西。
for循环一般格式有两种:
for 变量 in 列表
do
command 1
done
for ((i=1;i<=100;i++))
do
command 1
done
范例1:for循环数字1到5,使用for循环格式一
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
for i in {1..5}
do
echo $i
done
[root@cloucentos6 home]# ./test.sh
1
2
3
4
5
范例2:for循环数字1到5,使用for循环格式二
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
for ((i=1;i<=5;i++))
do
echo $i
done
[root@cloucentos6 home]# ./test.sh
1
2
3
4
5
范例3:for循环内嵌套if语句把数字1到10偶数输出。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
for i in {1..10}
do
if ((i%2==0))
then
echo $i
fi
done
[root@cloucentos6 home]# ./test.sh
2
4
6
8
10
范例4:for循环每个值默认以空格为分割,假如每个值不想以空格分割,可以使用双引号进行分割。
[root@cloucentos6 home]# cat test.sh
#!/bin/bashfor stat in what you name ? my name is Tomdoecho $statdone [root@cloucentos6 home]# ./test.sh whatyouname?mynameisTom
[root@cloucentos6 home]# cat test.sh
#!/bin/bashfor stat in "what you name ?" " my name is Tom"doecho $statdone [root@cloucentos6 home]# ./test.sh what you name ?my name is Tom
范例5:for语句嵌套if语句
[root@cloucentos6 home]# cat test.sh
#!/bin/bashfor file in /home/*doif [ -d "$file" ]thenecho "$file is a directory"elif [ -f "$file" ]thenecho "$file is a file"fidone [root@cloucentos6 home]# ./test.sh /home/abc is a file/home/closemysql.sh is a file/home/lost+found is a directory/home/test.sh is a file
6.6.2、while与until循环
Shell支持wile与until循环,与传统的程序语言的循环类似。格式如下:
while [ expression ]
do
command
done
until [expression]
do
command
done
讲解:
只要expression为false,while就会退出执行,否则,继续执行command语句。Until循环与while循环处理方式上刚好相反。只要expression为true,until就会退出执行,否则,继续执行command语句。一般while循环优于until循环,但在极少情况下,until循环更加有用。
范例1:while循环数字1到5输出。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
i=0
while ((i<5))
do
let i++
echo $i
done
[root@cloucentos6 home]# ./test.sh
1
2
3
4
5
范例2:until循环数字1到5输出。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
i=0
until ((i==5))
do
let i++
echo $i
done
[root@cloucentos6 home]# ./test.sh
1
2
3
4
5
6.6.3、break与contiune
Shell从C语言借用了break与continue命令,这个两个命令分别用来退出循环,或跳到循环体的其它地方。break命令允许跳出所有循环(终止后面所有循环),conntinue命令与break命令类似,只有一点差别,它不会跳出所有循环体,仅仅跳出当前循环。
范例1:break跳出所有循环(终止后面所有循环),if语句var1为4和var2为6就跳出全部循环体,break 2跳出两个循环体。如果break 1就是跳出一个循环体。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
for var1 in 2 4 6
do
for var2 in 1 6 7
do
if [ $var1 -eq 4 ] && [ $var2 -eq 6 ]
then
break 2
else
echo "$var1 $var2"
fi
done
done
[root@cloucentos6 home]# ./test.sh
2 1
2 6
2 7
4 1
范例2:continue命令仅仅跳出当前循环。
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
for var1 in 2 4
do
for var2 in 1 6
do
if [ $var1 -eq 4 ] && [ $var2 -eq 1 ]
then
continue
else
echo "$var1 $var2"
fi
done
done
[root@cloucentos6 home]# ./test.sh
2 1
2 6
4 6
6.7、函数
Bash和其他脚本语言一样支持函数,函数是指一段单独的程序代码,用于执行一些定义完整的单项工作。函数在使用之前必须先定义。函数一般定义格式:
定义函数
function test ()
{
echo “hello world!”
}
或者
test()
{
echo “hello world!”
}
函数可以以两种方式被引用:
Test ()
{
echo “$*”
}
test #直接引用
test 123 #带参数引用
标注:在函数体中,位置参数(如$1、$2、…..、$#、$*、$@等)都是函数的参数。
范例1:函数调用
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
function abc()
{
echo "hello world!"
}
abc
[root@cloucentos6 home]# ./test.sh
hello world!
参数可以传递给函数,并由脚本进行访问:
范例2:#通过运行test.sh脚本把 1 和 2参数传递到test.sh脚本的 $1 和 $2
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
function sum()
{
a1=$1
a2=$2
let var=$a1+$a2
echo 两数相加之和等于 "$var"
}
sum $1 $2
[root@cloucentos6 home]# ./test.sh 1 2
两数相加之和等于 3
范例3:命令行中传递参数给脚本中的函数
[root@cloucentos6 home]# cat test.sh
#!/bin/bash
function test ()
{
echo $(($1+$2))
}
if [ $# -eq 2 ]
then
test $1 $2
elif [ $# -eq 0 ]
then
echo "参数不能为空!"
else
echo "只能输入两个参数!"
fi
[root@cloucentos6 home]# ./test.sh
参数不能为空!
[root@cloucentos6 home]# ./test.sh 11 22 44
只能输入两个参数!
[root@cloucentos6 home]# ./test.sh 11 22
33