shell脚本编程for循环求阶乘_shell脚本循环及函数

16.循环执行

将代码段重复运行多次

重复运行多少次;

循环次数事先已知

循环次数事先未知

有进入条件和退出条件

for,while,until

for循环

for 变量名 in 列表;do

循环体

done

执行机制:

依次将列表中的元素赋值给“变量名”;每次赋值后即执行一次循环体;直到列表中的元素耗尽,循环结束

列表生成方式:

1.直接给出列表

2.整数列表:

(a){1..10}

(b) $(seq 1 10)

3.返回列表的命令

$(command)

4.使用glob,如*.sh

5.变量引用:$@,$*

案例练习:

1、判断/var/目录下所有文件的类型#!/bin/bash

#

a=`echo /var/ | sed -r 's@(.*)/@\1@'`

for b in `ls -A /var/`

do

c=`ls -dl $a/$b | cut -c1`

case $c in

f)

echo "$b iWJ"

;;

d)

echo "$b ML"

;;

*)

echo "$b NO ZD"

esac

done

2、添加10个用户user1-user10,密码同用户名#!/bin/bash

#

u=user1

for i in {1..10};do

if id -u $u$i &>/dev/null;then

echo "$u$i CZ"

else

useradd $u$i &> /dev/null

echo "$u$i useradd success!!"

echo $u$i |passwd --stdin $u$i &> /dev/null

echo "$u$i passwd success!!"

fi

done

3、/etc/rc.d/rc3.d目录下分别有多个以K开头和以S开头的 文件;分别读取每个文件,以K开头的文件输出为文件加stop ,以S开头的文件输出为文件名加start; “K34filename stop” “S66filename start”#!/bin/bash

#

file=`ls -A /etc/rc.d/rc3.d/`

for i in $file ;do

s=`echo $i | cut -c1`

case $s in

K)

echo "$i stop"

;;

S)

echo "$i start"

;;

esac

done

4、写一个脚本,提示输入正整数n的值,计算1+2+3+…n的 总和#!/bin/bash

#

read -p "SRSZ:" n

#m=`echo "$n" | grep -E "^[[:digit:]]+"`

if [ $n -eq 0 ];then

echo "zheshi 0"

fi

for i in `seq $n`

do

sum=$(($sum+$i))

done

echo `seq -s + 1 $n`=$sum

5、写一个脚本,提示请输入网络地址,如192.168.0.0,判 断输入的网段中主机在线状态#!/bin/bash

#

read -p  "shuru IP:" ip

num=`echo $ip |sed -r 's@(.*).$@\1@'`

if `echo $ip |egrep '\' &>/dev/null`

then

for i in `seq 113 116`

do

ping -c1 -W2 $num$i &>/dev/null && echo "$num$i success!" || echo "$num$i error"

done

else

echo "$ip bibi"

fi

6、打印九九乘法表#!/bin/bash

#

for i in `seq 9`

do

for b in `seq 1 $i`

do

echo -ne "$b*$i=$(($b*$i))\t"

done

echo

done

echo = = = = = = = = = = = = = = 2 = = = = = = = = = = = = =

for ((i=1; i<=9; i++))

do

for ((j=1; j<=i; j++))

do

echo -ne "$j*$i=$(($j*$i))\t"

done

echo

done

while 循环

while CONDITION;do

循环体

done

CONDITION:循环控制条件;进入循环之前,先做一次判断,每一次循环之后会在再次做判断,条件为“true”则执行一次循环,直到条件测试状态为false终止循环

CONDITION:一般应该有循环控制变量;而此变量的值会在循环体不断地被修正

进入条件:CONDITION为true;

退出条件:CONDITION为false;

案例练习:

1、求100以内所有正整数之和#!/bin/bash

#

declare -i SUM=0

declare -i I=0

while [ $I -le 100 ]

do

SUM+=$I

let I++

done

echo "$SUM"

2、通过ping命令探测172.16.250.1-254范围内的所有主机 的在线状态,统计在线主机和离线主机各多少。#!/bin/bash

#

ip=172.16.250.

i=1

c=0

s=0

while [ $i -lt 255 ];do

if ping -c1 -W2 $ip$i &>/dev/null;then

echo $ip$i sccuess

let c++

else

echo $ip$i  error

let s++

fi

let i++

done

echo sccuess:$c

echo error:$s

3、打印九九乘法表#!/bin/bash

#

declare -i i=1

while [ $i -le 9 ];do

declare -i j=1

while [ $j -le $i ];do

echo -ne "$j*$i=$(($j*$i))\t"

let j++

done

echo

let i++

done

4、利用变量RANDOM生成10个随机数字,输出这个10数字 ,并显示其中的最大者和最小者#!/bin/bash

#

declare -i i=0

q=`while [ $i -lt 10 ];do

s=$[$RANDOM]

echo $s

let i++

done`

b=`echo $q |tr " " "\n"|sort -n |head -1`

v=`echo $q |tr " " "\n"|sort -n |tail -1`

echo -e "D:$b\nX:$v"

5、打印国际象棋棋盘

#!/bin/bash

#

declare -i i=1

while [ $i -le 8 ];do

declare -i j=1

while [ $j -le 8 ];do

[ $[$i%2-$j%2] -eq 0 ] && echo -ne "\033[41m  \033[0m" ||echo -ne "\033[47m  \033[0m"

let j++

done

echo

let i++

done

until循环

until循环就是和while相反的,只需要把while的思路反过来即可

until CONDITION;do

循环体

done

进入条件:CONDITION为false

退出条件:CONDITION为true

循环控制语句continue

用于循环体重

continue[N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第一层

while CONDITION1;do

CMD1

...

if CONDITION2;then

CONDITION

fi

CMDN

....

done

循环控制语句break

用于循环体中

break[N]:提前结束第N层循环,最内层为第1层

while CONDITION1;do

CMD1

...

if CONDITION2;then

break

fi

CMDn

...

done

创建无线循环

while true;do

循环体

done

until false;do

循环体

done

案例练习:

1、每隔3秒钟到系统上获取已经登录的用户的信息;如果发 现用户hacker登录,则将登录时间和主机记录于日志 /var/log/login.log中,并提示该用户退出系统。#!/bin/bash

#

while true;do

who | grep hacker &> /dev/null

if [ $? -eq 0 ];then

who >> /var/log/login.log

echo  "hacker login exit!!!!"

exit

sleep 3

fi

done

2、随机生成10以内的数字,实现猜字游戏,提示比较大或小 ,相等则退出。#!/bin/bash

n=$[$RANDOM%10+1]

i=0

echo "猜数字游戏开始啦!"

while true

do

read -p "shuru:" in

let i++

if [ $in -eq $n ];then

echo "猜对喽! $n"

echo "一共猜了$i次"

exit 0

elif [ $in -gt $n ];then

echo "有点高了,数字小一点试试"

else

echo "有点小了,数字大一点试试"

fi

done

特殊用法

while循环的特殊用法(遍历文件的每一行)

while read line;do

循环体

done < /PATH/FROM/SOMEFILE

依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将每行赋值给变量line

案例练习:

1.扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填 充用户名和单位电话为62985600,并提示该用户的GECOS信 息修改成功#!/bin/bash

#

file="/etc/passwd"

while read line

do

u=$(echo $line |cut -d: -f1)

g=$(echo $line |cut -d: -f5)

chfn -f $u -p 62985600 $u &> /dev/null

if [ -z $g ];then

echo "$u GECOS sccuess"

else

echo "$u NOweikong"

#usermod -c "" $u

fi

done 

特殊用法:

双小括号方法:即((...))格式,也可以用于算术运算

双小括号方法也可以使bash shell 实现c语言风格的变量操作

#I=10

#((I++))

for循环的特殊格式:

for((控制变量初始化;条件判断表达式;控制变量的修正表达式))

do

循环体

done

控制变量初始化:仅在运行到循环代码段时执行一次

控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后在做条件判断

这种用法就像我们上面写的99乘法表一样,使用的是c语言风格的#!/bin/bash

#

for ((i=1; i<=9; i++))

do

for ((j=1; j<=i; j++))

do

echo -ne "$j*$i=$(($j*$i))\t"

done

echo

done

select循环与菜单

select variable in list

do

循环体命令

done

select循环主要用户创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示ps3提示符,等待用户输入。

用户输入菜单列表中的某个数字,执行相应的命令。

用户输入被保存在内置变量REPLY中

select 与 case

select是个无限循环,因此要记住用break命令退出循环,或用exit命令终止命令,也可以按ctrl+c来退出循环。

select经常和case联合使用

与for循环类似,可以省略 in list,此时使用位置参量。

函数介绍

函数function是由若干条shell命令组的语句块,实现代码重用和模块化编程。

它与shell程序形式上是相似的,不同的是它不是一个单独的 进程,不能独立运行,而是shell程序的一部分。

函数和shell程序比较相似,区别在于:

Shell程序在子Shell中运行

而Shell函数在当前Shell中运行。因此在当前Shell中,函数可以 对shell中变量进行修改

定义函数

函数由两部分组成:函数名和函数体。

语法一:

function f_name {

...函数体...

}

语法二:

f_name() {

...函数体...

}

函数的使用

函数的定义和使用:

可在交互式环境下定义函数

可将函数放在脚本文件中作为它的一部分

可放在只包含函数的单独文件中

调用:函数只有被调用才会执行;

调用:给定函数名

函数名出现的地方,会被自动替换为函数代码

函数的生命周期:被调用时创建,返回时终止

函数返回值

函数一共有两种返回值:

函数的执行结果返回值:

(1) 使用echo或printf命令进行输出

(2) 函数体中调用命令的输出结果

函数的退出状态码:

(1) 默认取决于函数中执行的最后一条命令的退出状态码

(2) 自定义退出状态码,其格式为:

return  从函数中返回,用最后状态命令决定返回值

return 0  无错误返回。

return 1-255  有错误返回

交互式环境下定义和使用函数

示例:

$dir() {

> ls -l

> }

定义该函数后,若在$后面键入dir,其显示结果同ls -l的 作用相同。

$dir

该dir函数将一直保留到用户从系统退出,或执行了如下 所示的unset命令: $ unset dir

在脚本中定义及使用函数

函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至 shell首次发现它后才能使用

调用函数仅使用其函数名即可。

示例: $cat func1

#!/bin/bash

# func1

hello()

{

echo "Hello there today's date is `date +%F`"

}

echo "now going to the function hello"

hello

echo "back from the function"

使用函数文件

可以将经常使用的函数存入函数文件,然后将函 数文件载入shell。

文件名可任意选取,但最好与相关任务有某种联 系。例如:functions.main

一旦函数文件载入shell,就可以在命令行或脚本 中调用函数。可以使用set命令查看所有定义的函 数,其输出列表包括已经载入shell的所有函数。

若要改动函数,首先用unset命令从shell中删除 函数。改动完毕后,再重新载入此文件。

函数文件示例:#!/bin/bash

#functions.main

findit()

{

if [ $# -lt 1 ] ;  then

echo "Usage:findit file"

return 1

fi

find / -name $1 –print

}

载入函数:

函数文件已创建好后,要将它载入shell

定位函数文件并载入shell的格式:. filename 或 source   filename

注意:此即  这里的文件名要带正确路径

示例:上例中的函数,可使用如下命令: $ . functions.main

检查载入函数:

使用set命令检查函数是否已载入。set命令将在shell中显示 所有的载入函数。

示例:$set

findit=( )

{

if [ $# -lt 1 ]; then

echo "usage :findit file";

return 1

fi

find / -name $1 -print

}

执行shell函数

要执行函数,简单地键入函数名即可:

示例:

$findit groups

/usr/bin/groups

/usr/local/backups/groups.bak

删除shell函数

现在对函数做一些改动。首先删除函数,使其对shell不可用 。使用unset命令完成此功能.

命令格式为: unset  function_name

示例:$unset findit 再键入set命令,函数将不再显示

函数参数:

函数可以接受参数:

传递参数给函数:调用函数时,在函数名后面以空白分隔 给定参数列表即可;例如“testfunc arg1 arg2 ...”

在函数体中当中,可使用$1, $2, ...调用这些参数;还 可以使用$@, $*, $#等特殊变量  函数变量

变量作用域:

环境变量:当前shell和子shell有效

本地变量:只在当前shell进程有效,为执行脚本会启动

专用子shell进程;因此,本地变量的作用范围是当前shell脚本 程序文件,包括脚本中的函数。

局部变量:函数的生命周期;函数结束时变量被自动销毁

注意:如果函数中有局部变量,如果其名称同本地变量,使 用局部变量。

在函数中定义局部变量的方法 local NAME=VALUE

函数递归:

函数直接或间接调用自身

注意递归层数

递归实例:

阶乘是基斯顿·卡曼于 1808 年发明的运算符号,是数学术语 一个正整数的阶乘(factorial)是所有小于及等于该数的正整 数的积,并且有0的阶乘为1。自然数n的阶乘写作n!。 n!=1×2×3×...×n。

阶乘亦可以递归方式定义:

0!=1

n!=(n-1)!×n

n!=n(n-1)(n-2)...1

n(n-1)! = n(n-1)(n-2)!

函数示例:#!/bin/bash

# fact()

{

if [ $1 -eq 0 -o $1 -eq 1 ]; then

echo 1

else

echo $[$1*$(fact $[$1-1])]

fi

}

fact $1

案例练习:

1、编写服务脚本/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为当前脚本名

(7)在所有模式下禁止启动该服务,可用chkconfig 和 service命令管理

#!/bin/bash

#

file=$(basename $0)

SCRIPTS="/var/lock/subsys/$file"

function start () {

if [ ! -e $SCRIPTS ];then

touch $SCRIPTS

sleep 1

echo "service $file start sccuess!"

else

echo "service $file running....."

fi

}

function stop () {

if [ -e $SCRIPTS ];then

rm -rf $SCRIPTS

sleep 1

echo "service $file stop sccuess!"

else

echo "service $file status  stop!"

fi

}

function status () {

if [ -e $SCRIPTS ];then

echo "$file is running..."

else

echo "$file is stopped..."

fi

}

case $1 in

start)

start

;;

stop)

stop

;;

restart)

stop

start

;;

status)

status

;;

*)

echo "$file usage {start|stop|status|restart}"

exit 1

;;

esac

2、编写脚本/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/ldlinux-x86-64.so.2

(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命 令,并重复完成上述功能;直到用户输入quit退出

#!/bin/bash

#

file=/mnt/sysroot/

libfile=/mnt/sysroot/lib64/

copycmd(){

[ -e /mnt/sysroot ] ||  mkdir /mnt/sysroot

cmd=`which --skip-alias $p`

cp $cmd $file && echo "Copy command success."

}

copylib(){

lib=$(ldd `which --skip-alias $p` |grep -E -o "/.*" | cut -d" " -f1)

cp $lib $libfile

[ $? -eq 0 ] && echo "Copy lib success."

}

while true

do

read -p " 请输入命令:" p

if [[ $p == "quit" ]];then

exit

fi

if which --skip-alias $p &> /dev/null ;then

copycmd

copylib

else

read -p " 不是命令, 请输入命令:" p

fi

done

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值