1
2
3
4
5
6
7
8
|
Bash编程之循环&函数
一、bash循环(
for
,
while
,until)
二、测试脚本
三、多分支
if
四、
case
语句的语法格式
五、function函数
六、变量作用域
七、函数递归
|
一、bash循环(for,while,until)
1.bash脚本编程
顺序执行
选择执行
循环执行
for,while,until,
进入条件:
for :列表元素非空
while :条件测试结果为“真”
until:条件测试结果为“假”
退出条件:
for:列表元素为空
while:条件测试结果为“假”
until:条件测试结果为“真”
2.循环控制语句:
while CONDATION1 ; do
CMD1
...
if CONDATION2;then
continue //结束本次循环
fi
CMDn
...
done
示例:求100以内所有偶数之和
3.创建循环体;
while true ;do
循环体
done
退出方式:某个测试条件满足时,让循环体执行break命令
break:直接跳出循环
continue:直接进入下一次循环
sleep 数字[时间单位] //默认是s,d:天,h:小时
4.while循环的特殊用法(遍历文件的行)
while read VAR; don
循环体
done < /path/to/somefile
依次读取/path/from/somefile文件中的每一行,且将某赋值给VAR变量
示例:脚本5
5.for循环的特殊用法
for ((控制变量初始化;条件判断表达式;控制var的修正语句))
循环体
done
控制变量初始化,仅在循环代码开始运行时执行一次
控制变量的修正语句;每轮循环结束会先进行控制变量修正运算,而后在根据判断条件判断
二、测试脚本
脚本1:求even:偶数,odd:奇数,100以内之和
1
2
3
4
5
6
7
8
9
10
11
12
|
#!/bin/bash
declare -i evensum=0 /
declare -i i=0
while
[ $i -le 100 ] ;
do
let
i++
//前面不能用let $i++
if
[ $[$i%2] -eq 0 ] ;then
//此处只能使用[ ] 进行引用
let
evensum+=$i
else
continue
fi
done
echo
"Even sum is $evensum"
|
//求所有奇数之和2500
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#!/bin/bash
declare -i evensum=0
declare -i i=0
while
[ $i -lt 100 ] ;
do
//必须是小于100,否则会出错
let
i++
if
[ $[$i%2] -eq 1 ] ;then
let
evensum+=$i
else
continue
fi
done
echo
"Even sum is $evensum"
|
脚本2:求和,break方式实现
1
2
3
4
5
6
7
8
9
10
11
|
#!/bin/bashk
declare -i oddsum=0
declare -i i=1
while
true
;
do
let
oddsum+=$i
let
i+=2
if
[ $i -gt 100 ];then
echo $oddsum
break
fi
done
|
脚本3:每个三s获取已经登录的用户信息,如果wolf用户已经登录,则记录于日志中,并退出
1
2
3
4
5
6
7
8
|
#!/bin/bash
while
true
;
do
if
who |grep wolf &> /dev/
null
; then
break
fi
sleep 3
done
echo
"$(date +%F-%H-%M) wolf loggin..."
>> /tmp/userlog.log
|
脚本4:util实现脚本3
1
2
3
4
5
|
#!/bin/bash
until who | grep
"wolf"
&> /dev/
null
;
do
sleep 3
done
echo
"$(date +%F-%H-%M) wolf loggin..."
>> /tmp/userlog.log
|
脚本5:当前os上id号为偶数的用户及其shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#!/bin/bash
declare -i userid
while
read i ;
do
userid=`echo $i | cut -d: -f3`
//注:同上userid=$(echo $i | cut -d: -f3)
if
[ $[$userid%2] -eq 0 ] ;then
echo $i | cut -d: -f1,7
fi
done < /etc/passwd
//另一种实现方式,while循环
#!/bin/bash
declare -i userid
while
read i ;
do
userid=$(echo $i | cut -d: -f3)
username=$(echo $i | cut -d: -f1)
usershell=$(echo $i | cut -d: -f7)
if
[ $[$userid%2] -eq 0 ] ;then
echo
"$username $userid $usershell"
fi
done < /etc/passwd
|
脚本6:for的特殊用法
1
2
3
4
5
6
|
#!/bin/bash
declare -i sum=0
for
((i=1;i<=100;i++));
do
let
sum+=$i
done
echo
"Sum: is .$sum"
|
脚本7;使用for的特殊用法,打印99表
1
2
3
4
5
6
7
8
|
#!/bin/bash
#
for
((i=1;i<=9;i++));
do
for
((j=1;j<=i;j++));
do
echo -e -n
"${i}*${j}=$[$i*$j]\t"
done
echo
//这个echo用于换行,因为前面不换行了
done
|
三、多分支if
多分支if
if condation1;then
..
elif
...
else
...
fi
单分支if
示例1:显示一个菜单给用户
要求:
1.提示用户给出自己的选择
2.正确的选择,则给出相应的信息,否则提示,用户重新选择
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#!/bin/bash
cat << EOF
cpu) display cpu information
mem) display memory information
disk) display disks information
quit) quit
===============================
EOF
read -p
"Enter your choice: "
opt
while
[
"$opt"
!=
"cpu"
-a
"$opt"
!=
"mem"
-a
"$opt"
!=
"disk"
-a
"$opt"
!=
"disk"
-a "$
opt
" != "
quit
" ] ;do read -p "
Enter your choice: " opt
done
if
[
"$opt"
==
"cpu"
] ;then
lscpu
elif [
"$opt"
==
"mem"
] ;then
free -m
elif [
"$opt"
==
"disk"
] ;then
fdisk -l /dev/sd[a-z]
else
echo
"quit"
exit 0
fi
|
四、case语句的语法格式
case $VAR in //仅仅支持glob风格的通配符
PAT1)
...
;; //双分号结尾
PAT2)
...
;; //
...
*)
...
;;
esac
注意:
case支持glob风格的通配符
*:任意长度的任意字符
?:任意单个字符
[]:范围内的
a|b :a或者b
case实现示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#!/bin/bash
cat << EOF
cpu) display cpu information
mem) display memory information
disk) display disks information
quit) quit
===============================
EOF
read -p
"Enter your choice: "
opt
while
[
"$opt"
!=
"cpu"
-a
"$opt"
!=
"mem"
-a
"$opt"
!=
"disk"
-a
"$opt"
!=
"disk"
-a "$
opt
" != "
quit
" ] ;do read -p "
Enter your choice: " opt
done
case
$opt
in
cpu)
//不用加“ ”
lscpu
;;
//最后要加 ;;
disk)
fdisk -l /dev/sd[a-z]
;;
mem)
free -m
;;
*)
echo
"quit"
exit 0 ;;
esac
|
五、function函数
过程式编程:代码重用
模块化编程
结构化编程
把一段独立功能的代码当做一个整体,并为之一个名字;命名的代码段,此即为函数
注意:定义函数的代码段不会自动执行,在调用时执行,所谓调用函数,在代码中给定函数名即可
函数名出现的任何位置,在代码执行时,都会被自动替换为函数代码
语法一:
function f_name () { //function和f_name之间有空格
...函数体...
}
语法二:
f_name() { //f_name() 中间没有空格
...函数体...
}
函数的生命周期:每次被调用时,返回时终止
其状态返回结果:函数体中运行的最后一条命令的状态结果;
自定义状态返回值:需要使用:return
return [0-255]
0:成功
1-255:失败
脚本使用:exit #作为其返回值
示例:脚本4
注意:在函数中,不能使用$1,$2,...因为具有特殊的意义
因为函数也可以接受参数,
$1,$2调用的是,传递给函数的参数,而不是脚本的参数
函数返回值
函数的执行结果返回值;
(1)使用echo或printf命令进行输出
printf不会自动换行,相当于echo -n
(2)函数体中调用的命令的执行结果
函数的退出状态码
1.默认取决于函数最后执行的那一条命令
2.自定义的方法,return
函数可以接受参数
传递参数给函数
1.在函数体中,可以使用$1,$2,...引用传递给函数的参数;
$*和$@调用所有参数,
$#引用参数个数
2.在调用函数时,在函数名后以空白字符分隔给定参数列表即可,例如:a b c d
六、变量作用域
局部变量:作用域是函数的声明周期
定义:locale VARIABLE=VALUE
本地变量:作用域是运行脚本的shell的生命周期;作用范围是当前shell程序
a=VALUE //
全局变量:
环境变量:
全局变量和局部变量对比:
1
2
3
4
5
6
7
8
9
10
11
|
#!/bin/bash
name=tom
setname() {
local name=jerry
echo
"Function name:$name"
}
setname
echo
"Shell: $name"
[root@localhost ~]# bash 2.sh
Function name:jerry
Shell: tom
|
七、函数递归 //自己调用自己
函数间接或者直接就调用自身
10!=10*9!=10*9*8!=...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#!/bin/bash
fact() {
if
[ $1 -eq 0 -o $1 -eq 1 ] ;then
//[ $1 -eq 0 ] || [ $1 -eq 1 ] 这样也可以
echo $1
else
echo $[$1*$(fact $[$1-1])]
fi
}
fact $1
#!/bin/bash
fab() {
if
[ $1 -eq 1 ] ;then
echo -n
"1 "
elif [ $1 -eq 2 ] ;then
echo -n
"1 "
else
echo -n
"$[$(fab $[$1-1]+$(fab $[$1-2])]"
fi
}
for
i
in
$(seq 1 $1) ;
do
fab $i
done
echo
|
服务启动服务框架
$lockfile,值/var/lock/subsys/SCRIPT_NAME
1.可以接受的参数start,stop,restart,status四个参数
2.如果参数非此四个,则显示帮助后退出
3.start,创建lockfile,并显示启动:stop,则创建lockfile,并显示停止;restart,则先删除此文件,再创建此文件,而后显示重启完成,;
statue根据lockfile是否存在,显示running/stopped
注:务必使用case语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#!/bin/bash
#
# chkconfig: - 50 50
# description test_service_script
prog=$(basename $0)
lockfile=/
var
/
lock
/subsys/$prog
case
$1
in
start)
if
[ -f $lockfile ] ;then
echo
"$prog is running yet."
else
touch $lockfile
[ $? -eq 0 ] && echo
"Start $prog finished.."
fi
;;
stop)
if
[ -f $lockfile ] ;then
rm -f $lockfile
[ $? -eq 0 ] && echo
"$prog stopped.."
else
echo
"$prog is not running.."
fi
;;
restart)
if
[ -f $lockfile ] ; then
rm -f $lockfile
touch $lockfile
echo
"$prog restart finished.."
else
touch $lockfile
echo
"$prog start finished.."
fi
;;
status)
if
[ -f $lockfile ] ;then
echo
"$prog is running.."
else
echo
"$prog is stopped.."
fi
;;
*)
echo
"Usage: $prog {start|stop|resatrt|status}"
esac
cp service /etc/init.d/service
chmod +w /etc/init.d/service
chkconfig --add service
service service start
|
八、function脚本
1.给定一个用户名,获取其id和shell
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#!/bin/bash
#
userinfo() {
if
id
"$username"
&> /dev/
null
;then
grep
"$username"
/etc/passwd | cut -d: -f3,7
else
echo
"No $username such user.."
fi
}
username=$1
userinfo
//调用该函数,可以调用多次
username=$2
userinfo
|
2.升级版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#!/bin/bash
#
# chkconfig: - 50 50
# description test_service_script
prog=$(basename $0)
lockfile=/
var
/
lock
/subsys/$prog
start() {
if
[ -f $lockfile ] ;then
echo
"$prog is running yet."
else
touch $lockfile
[ $? -eq 0 ] && echo
"Start $prog finished.."
fi
}
stop() {
if
[ -f $lockfile ] ;then
rm -f $lockfile
[ $? -eq 0 ] && echo
"$prog stopped.."
else
echo
"$prog is not running.."
fi
}
restart() {
if
[ -f $lockfile ] ; then
rm -f $lockfile
touch $lockfile
echo
"$prog restart finished.."
else
touch $lockfile
echo
"$prog start finished.."
fi
}
status() {
if
[ -f $lockfile ] ;then
echo
"$prog is running.."
else
echo
"$prog is stopped.."
fi
}
usage() {
echo
"Usage: $prog {start|stop|resatrt|status}"
}
case
$1
in
start)
start ;;
stop)
stop ;;
restart)
restart;;
status)
status;;
*)
usage;;
esac
|
3.添加10个用户
添加用户的功能用函数实现,用户名作为参数传递给函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#!/bin/bash
#
# 5: user is exists
#
#
adduser() {
if
id $1 &> /dev/
null
; then
return
5
else
useradd $1
retval=$?
return
$retval
fi
}
for
i
in
{1..10} ;
do
adduser ${1}$i
a=$?
//$?不要直接引用,如果需要多次引用的话,进行赋值变量
if
[ $a -eq 0 ] ;then
echo
"useradd succeed..."
elif [ $a -eq 5 ] ;then
echo
"user ${1}$i is exists ,useradd failure."
else
echo
"Unknown errors.."
fi
done
|