for 循环
for 变量名 in 列表;do
循环体
done
执行机制: 依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中
的元素耗尽,循环结束
列表生成方式:
(1)直接给出列表
(2)整数列表:
(a) {start..end}
(b) $(seq [start [step]] end) 例: `seq 1 2 100`
(3)返回列表的命令 $(COMMAND)
(4)使用glob,如:*.sh
(5)变量引用;$@, $*
while 循环
while CONDITION;do
循环体
done
CONDITION :循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判 断;条件为“true”则执行一次循环;直到条件测试状态为“false”终止循环
因此:CONDTION 一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
进入条件:CONDITION 为true; 退出条件:CONDITION 为false
until 循环
until CONDITION;do
循环体
done
进入条件:CONDITION 为true; 退出条件:CONDITION 为false
循环控制语句continue
用于循环体中
continue [N] :提前结束第N 层的本轮循环,而直接进入下一轮判断;最内层为第1层
while CONDTIITON1; do
CMD1
…
if CONDITION2; then
continue
fi
CMDn
…
done
循环控制语句break
用于循环体中
break [N] :提前结束第N 层循环,最内层为第1层
while CONDTIITON1; do
CMD1
…
if CONDITION2; then
break
fi
CMDn
…
done
创建无线循环
while true;do
循环体
done
until false;do
循环体
done
while 循环的特殊用法(遍历文件的每一行)
while read line; do
循环体
done < /PATH/FROM/SOMEFILE
依次读取/PATH/FROM/SOMEFILE 文件中的每一行,且将行赋值给变量line
for 循环的特殊格式:
for (( 控制变量初始化; 条件判断表达式; 控制变量的修正表达式))
do
循环体
done
控制变量初始化:仅在运行到循环代码段时执行一次
控制变量的修正表达式: 每轮循环结束会先进行控制变量修正运算,而后再做条件判断
双小括号方法,即((…)) 格式,如((i=1,i++,i<=10))
例:
打印3次10~20(排除15)
continue改为continue 2 或break 跳出里面的for循环,则打印3次10~14
若改为break 2,则跳出整个循环,只打印10~14
select循环与菜单
select variable in list
do
循环体命令
done
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3提示
示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量 REPLY中
select是个无限循环,因此要记住用break命令退出循环,或用 exit命令终止脚本,
也可以按 ctrl+c退出循环。select 经常和case联合使用
例1: select cmd in ls pwd hostname exit;do $cmd;done
注意:输入4,执行exit就登出shell了
例2
函数
function f_name {
函数体
}
或
f_name() {
函数体
}
函数的定义和使用:
可在交互式环境下定义函数
可将函数放在脚本文件中作为它的一部分
可放在只包含函数的单独文件中
调用:函数只有被调用才会执行;
调用:给定函数名
函数名出现的地方,会被自动替换为函数代码
函数的生命周期:被调用时创建,返回时终止
函数的执行结果返回值:
(1) 使用echo 或printf 命令进行输出
(2) 函数体中调用命令的输出结果
函数的退出状态码:
(1) 默认取决于函数中执行的最后一条命令的退出状态码
(2) 自定义退出状态码,其格式为:
return 从函数中返回,用最后状态命令决定返回值
return 0 无错误返回
return 1-255 有错误返回
使用函数文件
可以将经常使用的函数存入函数文件,然后将函数文件载入shell
一旦函数文件载入shell,就可以在命令行或脚本中调用函数。可以使用set命令查看所有定义的函数,其输出列表包括已经载入shell 的所有函数;若要改动函数,首先用unset命令从shell中删除函数,改动完毕后,再重新载入此文件
function fun1 (){ echo "this is a fun1";}
# fun1 输出this is a fun1
set命令看到存在内存中的变量fun1
unset fun1 再set查看就没有这个变量了,# fun1 输出command not found
function fun3 () { echo "this is a func3";return;echo "xxxx"; }
#fun3 只输出this is a func3 return后面的不执行
echo $? 返回0
return后面自定义级别,如return 100
执行fun3 再echo $? 返回100
载入函数
. filename 或 source filename
函数变量
变量作用域:
环境变量:当前shell和子shell有效
本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此本地变量的作用范围是当前shell 脚本程序文件,包括脚本中的函数。
局部变量:函数的生命周期;函数结束时变量被自动销毁
注意:如果函数中有局部变量,如果其名称同本地变量,使用局部变量
在函数中定义局部变量的方法 local NAME=VALUE
1.判断/var/ 目录下所有文件的类型
for i in /var/*;do echo $i|filetype.sh;done |sed -n '2~2p' (用到函数调用)
2.添加10个用户user1-user10,密码同用户名
#!/bin/bash
for i in {1..10}
do
useradd user$i
echo "user$i"|passwd –stdin user$i
done
3./etc/rc.d/rc3.d 目录下分别有多个以K开头和以S开头的文件;分别读取每个文件,以K 开头的文件输出为文件加stop,以S开头的文件输出为文件名加start;
“K34filename stop” “S66filename start”
#!/bin/bash
cd /etc/rc.d/rc3.d
for i in /etc/rc.d/rc3.d/*;do
b=`basename /etc/rc.d/rc3.d/$i`
j=`echo $b|cut -c1`
if [ $j == 'K' ];then
cp $b "$b"_stop
elif [ $j == 'S' ];then
cp $b "$b"_start
fi
done
4.写一个脚本,提示输入正整数n 的值,计算1+2+3+…n的总和
#!/bin/bash
read -p "Input a positive number: " n
if [ $[$n/1] -gt 0 ];then
echo sum=`seq -s+ 1 $n|bc`
elif [ $[$n/1] -lt 0 ];then
echo negative number is not allowed
elif [ $n == 0 ];then
echo Zero!
else
echo other input is illegal
fi
5.写一个脚本,提示请输入网络地址,如172.18.18.0 ,判断输入的网段中主机在线状态
#!/bin/bash
for ip in `seq 1 255`
do
{
ping -c 1 172.18.18.$ip > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo 172.18.18.$ip UP
else
echo 172.18.18.$ip DOWN
fi
}&
done
6.打印乘法表(if / while)
#!/bin/sh
for i in {1..9};do
for ((j=1;j<=9;j++));do
echo -n "$j*$i=$(($j*$i)) "
if [ $j -ge $i ];then
echo
break
fi
done
done
或
#!/bin/sh
i=1
j=1
while [ "$i" -ne 10 ];do
while [ "$j" -le $i ];do
echo -ne "$i*$j=$(($i*$i)) \t"
let j++
done
j=1
let i++
echo
done
7.求100以内所有正整数之和(while)
#!/bin/bash
read -p "Input a positive number: " n
a=0
while [ $a -le $n ];do
sum=`seq -s+ 1 $a`
let a++
done
echo $sum|bc
8.通过ping 命令探测192.168.1.1-254范围内的所有主机的在线状态,统计在线主机和离线主机各多少
#!/bin/bash
read -p "Input the ip: " ip
i=`echo $ip | cut -d. -f1-3`.
j=0
if echo $ip | egrep "^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){2}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$" ;then
while [ $j -le 255 ] ;do
ping -c1 -W1 $i$j &> /dev/null && echo "$i$j is online" ||echo "$i$j is offline"
let j++
done
else
echo "Illegal input"
fi
9.利用变量RANDOM生成10个随机数字,输出这个10数字,并显示其中的最大者和最小者(while)
#!/bin/bash
echo > rnu
frequency=1
while [ $frequency -le 10 ];do
echo $[$RANDOM] >> rnu
let frequency++
done
ten_random=`cat rnu|sed -e 1d`
echo "Ten random number are"
echo $ten_random
echo -e "\033[31mmax=`cat rnu|tr " " "\n"|sort -n|tail -1`\033[0m"
echo -e "\033[32mmin=`cat rnu|tr " " "\n"|sort -n|sed -n 2p`\033[0m"
10.打印国际象棋棋盘
#!/bin/bash
for i in {1..8}; do
for ((j=1;j<=8;j++)); do
if [ $[($i+$j)%2] -eq 0 ]; then
echo -ne "\033[47m \033[0m"
else
echo -ne "\033[40m \033[0m"
fi
if [ $j -eq 8 ]; then
echo -ne "\n"
fi
done
done
11.每隔3秒钟到系统上获取已经登录的用户的信息;如果发现用户hacker 登录,则将登录时 间和主机记录于日志/var/log/login.log 中, 并提示该用户退出系统
#!/bin/bash
until who |grep -q "^hacker\b" ;do
sleep 3
done
who | grep "^hacker"|tr -s ' '|cut -d' ' -f3,5 >> /var/log/login.log
echo "you should logout system" | mail hacker
echo "reminded and login record in /var/log/login.log"
12. 随机生成10以内的数字,实现猜字游戏,提示比较大或小,相等则退出。
#!/bin/bash
read -p "Input a number: " m
n=$[$RANDOM%10+1]
until [[ $m -eq $n ]];do
[ $m -lt $n ] && echo "It's small,guess bigger"
[ $m -gt $n ] && echo "It's big,guess smaller"
read -p "Input a number: " m
done
echo Right!
13.打印松塔
#!/bin/bash
#i是当前行数,j是空格数量,h是星号数量
read -p "Please Enter a number:" Row
for ((i=1; i<=Row; i++))
do
for ((j=$Row-$i; j>0; j–));
do
echo -n ' '
done
for ((h=1; h<=$((2*$i-1)); h++))
do
echo -ne '\033[32m*\033[0m'
done
echo
done
14.用until循环实现国际象棋棋盘
#!/bin/bash
i=1
j=1
until [ $i -gt 8 ]
do
until [ $j -gt 8 ]
do
if [ $[(($i+$j))%2] -eq 1 ];then
echo -ne "\033[47m \033[0m"
else
echo -ne "\033[40m \033[0m"
fi
let j++
done
echo
let i++
j=1
done
15.编写服务脚本/root/bin/testsrv.sh,完成如下要求
(1) 脚本可接受参数:start, stop, restart, status
(2) 如果参数非此四者之一,提示使用格式后报错退出
(3) 如是start:则创建/var/lock/subsys/SCRIPT_NAME, 并显示“启动成功”
考虑:如果事先已经启动过一次,该如何处理?
(4) 如是stop:则删除/var/lock/subsys/SCRIPT_NAME, 并显示“停止完成”
考虑:如果事先已然停止过了,该如何处理?
(5) 如是restart,则先stop, 再start
考虑:如果本来没有start,如何处理?
(6) 如是status, 则如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAME is running…”
如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is stopped…”
其中:SCRIPT_NAME为当前脚本名
#!/bin/bash
fstart () {
if [ -e "$1" ]; then
echo "Already start"
else
touch $ff
echo "Start Successfully!"
fi
}
fstop () {
if [ -e "$1" ] ; then
rm -f $1
echo "Stop Successfully!"
else
echo "Already stop"
fi
}
frestart() {
if [ -e "$1" ] ; then
fstop &> /dev/null
fstart &> /dev/null
echo "Restart successful"
else
fstart &> /dev/null
echo "start successful "
fi
}
fstatus () {
if [ -e "$1" ] ;then
echo "testsrv is runing…"
else
echo "testsrv is stopped…"
fi
}
select choice in start stop restart status quit
do
ff=/var/lock/subsys/testsrv.sh
case $choice in
start)
fstart $ff
;;
stop)
fstop $ff
;;
restart)
frestart $ff
;;
status)
fstatus $ff
;;
quit)
break
;;
*)
echo "error!"
exit 2
esac
done
16. 编写脚本/root/bin/copycmd.sh
(1)提示用户输入一个可执行命令名称;
(2)获取此命令所依赖到的所有库文件列表
(3)复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下;
如:/bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd==> /mnt/sysroot/usr/bin/passwd
(4)复制此命令依赖到的所有库文件至目标目录下的对应路径下:
如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上 述功能;直到用户输入quit退出
#!/bin/bash
copycmd(){
for eachline in `ldd $fullname | sed -r -n 's@.*> (/.*) \(.*$@\1@p'`
do
local path=`dirname $eachline`
mkdir -p /mnt/sysroot/$path &>/dev/null
cp -p $eachline /mnt/sysroot/$path &>/dev/null
done
}
while true
do
read -p "请输入一个可执行的命令名称 " cmds
which $cmds
if [ $? -eq 0 ]
then
fullname=`\which $cmds`
path=`dirname $fullname`
mkdir -p /mnt/sysroot/$path &>/dev/null
cp -p $fullname /mnt/sysroot/$path &>/dev/null
copycmd
elif [[ $cmds == "quit" ]]
then
break
else
echo "输入的命令不对"
fi
done
17.写一个函数实现数字的加减乘除运算,例如输入1+2 ,将得出正确结果
vim mathfun
#!/bin/bash
function multiplications () {
let multiplication=$1\*$2
echo "积为:$multiplication"
}
function divisions () {
let division=$1/$2
echo "商为:$division"
}
function pluss () {
let plus=$1+$2
echo "和为:$plus"
}
function subtractions {
let subtraction=$1-$2
echo "差为:$subtraction"
}
vim funset
#!/bin/bash
source mathfun
echo "1st arg is $1"
echo "2st arg is $2"
pluss $1 $2
divisions $1 $2
multiplications $1 $2
subtractions $1 $2
18. 0,1,2,3,5,8,13,21,34…… ,斐波纳契数列以如下被以递归的方法定义:
F(0)=0 ,F(1)=1 ,F(0)=F(n-1)+F(n-2) (n≥2)
写一个函数,求n阶斐波那契数列
#!/bin/bash
rabbit() {
if [ $1 -eq 0 ];then
echo 0
elif [ $1 -eq 1 ];then
echo 1
else
echo "$[$(rabbit $[$1-1])+$(rabbit $[$1-2])]"
fi
}
rabbit $1
19.利用函数,实现N片盘的汉诺塔的移动步骤
#!/bin/bash
hannuo() {
if [ $1 -eq 1 ];then
echo "from $2 to $4"
else
hannuo `expr $1 – 1` $2 $4 $3
echo "from $2 to $4"
hannuo `expr $1 – 1` $3 $2 $4
fi
}
read -p "Input the number: " n
hannuo $n 'A' 'B' 'C'
20.扫描/etc/passwd 文件每一行,如发现GECOS 字段为空,则填充用户名和单位电话为62985 6,并提示该用户的GECOS信息修改成功
#!/bin/bash
while read line ; do
var=`echo $line | cut -d ":" -f 5`
user=`echo $line | cut -d ":" -f 1`
[[ -z "${var}" ]] && chfn -f ${user} -p 629856 ${user};echo "${user}'s information
change successful"
done < /etc/passwd
原创文章,作者:victorycommander,如若转载,请注明出处:http://www.178linux.com/39013