Shell脚本中select、函数总结

描述:

select控制语句基于Korn Shell中的控制结构

select语句首先显示一个菜单,然后根据用户的选择给变量赋予相应的值,最后执行一系列命令。

语法:

select varname [ in arg…]

do

   commands

done

说明:

select结构显示arg项的菜单。加入忽略关键字in和参数列表,select控制语句就用位置参数来取代arg项。select的菜单格式化为在每一项前加一个数字。

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

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

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

select是个无限循环,使用break命令退出循环,或用exit命令终止脚本,也可以按ctrl+c推出循环

select经常和case联合使用

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

示例:

#!/bin/bash
PS3="Please guss which fruit I like:"
select var in "apple" "pear" "orange" "peach";do
  if [ "$var" == "apple" ];then
    echo "You are right"
    break
  else
    echo "try again"
  fi  
done
[root@localhost ~]# bash a.sh 
1) apple
2) pear
3) orange
4) peach
Please guss which fruit I like:2
try again
Please guss which fruit I like:3
try again
Please guss which fruit I like:4
try again
Please guss which fruit I like:1
You are right

函数:

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

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

函数和shell程序的区别在于:

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

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

语法一:

function NAME {

  函数体

}

语法二:

NAME() {

  函数体

}

函数的使用:

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

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

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

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

   调用:给定函数名

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

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

函数的执行结果返回值:

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

  2,函数体调用命令的输出结果

函数的退出状态码:

  1,默认取决于函数最后一条命令的退出状态码

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

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

  return 0 正确返回

  return 1-255 有错误返回

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

示例:

[root@localhost ~]# dir(){   
> ls -l            定义该函数后,在命令行直接键入dir,其显示结果同ls -l的作用相同
> }
[root@localhost ~]# dir
-rw-r--r--. 1 root root  205 Aug 19 17:55 a.sh
-rwxr-xr-x. 1 root root  106 Aug 12 05:42 backup.sh
drwxr-xr-x. 2 root root 4096 Aug 15 06:28 bin
[root@localhost ~]# unset dir    从当前系统中退出该dir函数

在脚本中定义及使用函数

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

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

示例:

[root@localhost ~]# 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"
[root@localhost ~]# chmod +x func1
[root@localhost ~]# ./func1
now going to the function hello
Hello there today's date is 2016-08-21
back from the function

使用函数文件

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

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

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

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

创建函数文件:

示例:

[root@localhost ~]# cat function.main       函数文件
#!/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   (即<点> <空格> <文件名>)   (这里的文件名要带正确路径)

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

[root@localhost ~]# . function.main
[root@localhost ~]# set
findit () 
{ 
    if [ $# -lt 1 ]; then
        echo "Usage:findit file";
        return 1;
    fi;
    find / -name $1 -print
}
[root@localhost ~]# findit groups   执行shell函数,键入函数名即可
/usr/bin/groups
[root@localhost ~]# unset findit     删除shell函数(命令格式为:unset function_name)
[root@localhost ~]# set     函数findit无显示

函数参数:

传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如:"findit a b …"

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

函数变量:

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

  本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数

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

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

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

函数递归示例:

[root@localhost ~]# cat fact.sh 
#!/bin/bash
fact() {
  if [ $1 -eq 0 -o $1 -eq 1 ];then
echo 1
  else
echo $[$1*$(fact $[$1-1])]
  fi
}
fact 4
[root@localhost ~]# bash -x fact.sh 
+ fact 4
+ '[' 4 -eq 0 -o 4 -eq 1 ']'
++ fact 3
++ '[' 3 -eq 0 -o 3 -eq 1 ']'
+++ fact 2
+++ '[' 2 -eq 0 -o 2 -eq 1 ']'
++++ fact 1
++++ '[' 1 -eq 0 -o 1 -eq 1 ']'
++++ echo 1
+++ echo 2
++ echo 6
+ echo 24
24

作业:

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为当前脚本名

[root@localhost function]# cat testsrv.sh 
#!/bin/bash
fstart () {
  if [ -e "$1" ];then
     echo "Already Start"
  else
     touch $File
     echo "Start Successfully!"
  fi
}
fstop() {
  if [ -e "$1" ];then
     rm -f $File
     echo "Stop Successfully!"
  else
     echo "Already stop"
  fi
}
frestart() {
  if [ -e "$1" ];then
     fstop &> /dev/null
     fstart &> /dev/null
     echo "Restart Successfully!"
  else
     fstart &> /dev/null
     echo "Start Successfully!"
  fi
}
fstatus() {
  if [ -e "$1" ];then
     echo "testsrv is running"
  else
     echo "testsrv has been stop"
  fi
}
select choice in start stop restart status quit;do
  File=/var/lock/subsys/testsrv.sh
    case $choice in
    start)
       fstart $File
       ;;
    stop)
       fstop $File
       ;;
    restart)
       frestart $File
       ;;
    status)
       fstatus $File
       ;;
    quit)
       break
       ;;
     *)
       echo "error,please choose again"
       exit 2
     esac
done 
[root@localhost function]# bash testsrv.sh 
1) start
2) stop
3) restart
4) status
5) quit
#? 4
testsrv is running
#? 3
Restart Successfully!
#? 1
Already Start
#? 2
Stop Successfully!
#? 5

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退出

[root@localhost ~]# cat copycmd.sh 
#!/bin/bash
ch_root="/mnt/sysroot/"
[ ! -d $ch_root ] && mkdir $ch_root
bincopy() {
   if which $1 &>/dev/null;then
      local cmd_path=`which --skip-alias $1`
      local bin_dir=`dirname $cmd_path`
      [ -d ${ch_root}${bin_dir} ] || mkdir -p ${ch_root}${bin_dir}
      [ -f ${ch_root}${cmd_path} ] || cp $cmd_path ${ch_root}${bin_dir}
      return 0
   else
      echo "Command not found"
      return
   fi
}
libcopy() {
   local lib_list=$(ldd `which --skip-alias $1` | grep -Eo '/[^[:space:]]+')
   for loop in $lib_list;do
       local lib_dir=`dirname $loop`
       [ -d ${ch_root}${lib_dir} ] || mkdir -p ${ch_root}${lib_dir}
       [ -f ${ch_root}${loop} ] || cp $loop ${ch_root}${lib_dir}
   done
}
read -p "Please input a command:" command
while [ "$command" != "quit" ];do
    if bincopy $command;then
         libcopy $command
    fi
    read -p "Please input a command or quit:" command
done
[root@localhost ~]# ll /mnt/sysroot/lib64
-rwxr-xr-x. 1 root root  164432 Aug 23 15:28 ld-linux-x86-64.so.2
-rwxr-xr-x. 1 root root   37056 Aug 23 15:28 libacl.so.1
-rwxr-xr-x. 1 root root   19888 Aug 23 15:28 libattr.so.1
-rwxr-xr-x. 1 root root   20024 Aug 23 15:28 libcap.so.2
-rwxr-xr-x. 1 root root 2107816 Aug 23 15:28 libc.so.6
-rwxr-xr-x. 1 root root   19512 Aug 23 15:28 libdl.so.2
-rwxr-xr-x. 1 root root  153192 Aug 23 15:28 liblzma.so.5
-rwxr-xr-x. 1 root root  398272 Aug 23 15:28 libpcre.so.1
-rwxr-xr-x. 1 root root  142296 Aug 23 15:28 libpthread.so.0
-rwxr-xr-x. 1 root root  147120 Aug 23 15:28 libselinux.so.1
[root@localhost ~]# ll /mnt/sysroot/usr/bin
-rwxr-xr-x. 1 root root  54048 Aug 23 15:41 cat
-rwxr-xr-x. 1 root root 117616 Aug 23 15:35 ls

3、写一个函数实现两个数字做为参数,返回最大值

#!/bin/bash
function NUMBER {
 if [ $1 -lt $2 ];then
    echo "The max number is $2"
 elif [ $1 -eq $2 ];then
    echo "The two number is equal"
 else
    echo "The max number is $1"
 fi
}
NUMBER $1 $2
[root@localhost function]# bash test3.sh 3 5
The max number is 5
[root@localhost function]# bash test3.sh 6 4
The max number is 6
[root@localhost function]# bash test3.sh 8 8
The two number is equal

4、写一个函数实现数字的加减乘除运算,例如输入 1 + 2,将得出正确结果

[root@localhost function]# cat test4-1.sh 
#!/bin/bash
fjia() {
   sum=$[$1+$2]
   echo "$sum"
}
fjian() {
   sum=$[$1-$2]
   echo "$sum"
}
fcheng() {
   sum=$[$1*$2]
   echo "$sum"
}
fchu() {
   sum=$[$1/$2]
   echo "$sum"
}
read -p "please input: " a b c
   case $b in
   +)
      fjia $a $c
      ;;
   -)
      fjian $a $c
      ;;
   \*)
      fcheng $a $c
      ;;
   /)
      fchu $a $c
      ;;
   *)
      echo "please input correct form"
      exit 3
   esac
[root@localhost function]# bash test4-1.sh 
please input: 6+7
please input correct form
please input: 6 + 7
13 
please input: 6 - 8   
-2
please input: 2 * 3
6
please input: 4 / 2
2

5、斐波那契数列又称黄金分割数列,因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列: 0、 1、 1、 2、 3、 5、 8、 13、 21、 34、 ……,斐波纳契数列以如下被以递归的方法定义: F( 0) =0, F( 1) =1, F( n) =F(n-1)+F(n-2)(n≥2)

写一个函数,求n阶斐波那契数列

[root@localhost function]# cat test5-1.sh 
#!/bin/bash
ftzsl() {
   if [ $1 -eq 0 ];then
      echo "0"
   elif [ $1 -eq 1 ];then
      echo "1"
   else
      echo "$[$(ftzsl $[$1-1])+$(ftzsl $[$1-2])]"
   fi
}
read -p "please input a number: " n
   ftzsl $n
[root@localhost function]# bash test5-1.sh 
please input a number: 5
5 
please input a number: 6
8

6、汉诺塔(又称河内塔)问题是源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间

一次只能移动一个圆盘。利用函数,实现N片盘的汉诺塔的移动步骤

[root@localhost function]# cat test6.sh 
#!/bin/bash
fpan() {
  if [ $1 -eq 1 ];then
     echo "$2 ==> $4"
  else
     fpan $[$1-1] $2 $4 $3
          echo "$2 ==> $4"
     fpan $[$1-1] $3 $2 $4
  fi
}
fpan $1 a b c 
[root@localhost function]# bash test6.sh 2
a ==> b
a ==> c
b ==> c

原创文章,作者:pingsky,如若转载,请注明出处:http://www.178linux.com/38881

(0)
pingskypingsky
上一篇 2016-08-24
下一篇 2016-08-24

相关推荐

  • 马哥教育Net20第二十二天:在Centos7上实现lmnp

    要求: vhost1: pma.stuX.com, phpMyAdmin, 同时提供https服务; vhost2: wp.stuX.com, wordpress vhost3: dz.stuX.com, Discuz  环境说明: DNS是:192.168.100.7 vhos…

    Linux干货 2016-07-02
  • CA和证书

    A与B双方通信,需要通过签证机构CA颁发证书,才可以互相信任,从而安全的进行数据传输。想要获取证书,除了付费购买认证机构的证书,还可以自签名获取证书。 openssl命令可以搭建CA,实现自签名证书。下面以三台主机为例,模拟根CA、子CA的搭建,以及客户端申请证书的过程。 一、搭建根CA /etc/pki/tls/openssl.cnf文件是openssl的…

    2017-09-10
  • 第六周学习总结

    写在前面 在互联网+的时代,网络显得越发重要,如果现在你一顿不吃饭可能还没事但是一个小时没网络,估计你都要疯了。那么网络到底是个啥呢?看不见又摸不着。拿着一台电脑怎么和网络建立连接呢?那么下面要讲解的内容或许可以给你解决个大概。 闲聊网络 如果让你修一栋房子你会一层一层的往上修,并且规划好一层用来开商铺,二层用来开超市,上面一层用来干嘛等等,其实网络也是一样…

    2018-01-08
  • Linux系统启动过程及其修复过程简析

    Linux组成 Linux: kernel+rootfs     kernel: 进程管理、内存管理、网络管理、驱动程序、文件系统、安全功能     rootfs:程序和glibc     库:函数集合, function, 调用接口(头文…

    Linux干货 2016-09-19
  • MySQL-MMM安装指南(Multi-Master Replication Manager for MySQL)

    最基本的MMM安装必须至少需要2个数据库服务器和一个监控服务器下面要配置的MySQL Cluster环境包含四台数据库服务器和一台监控服务器,如下: function ip hostname server id monitoring host 192.168.0.10 mon – master 1 192.168.0.11 db1 1 maste…

    Linux干货 2015-05-01
  • 初涉Linux基本要点概括(1)

    计算机,这里通常指可以储存程序的计算机,根据冯诺依曼体系,计算机组成部件包括控制单元(Control Unit)、算术逻辑单元(Arithmetic Logic Unit)、内存(Memory)、输入设备(Input)、输出设备(Output)。计算机通过输入的数据和指令,可以完成各种复杂的运算任务,小到文字处理、游戏、影音、大到卫星定位,火箭发射,人工智能…

    Linux干货 2016-09-26