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 10:12
下一篇 2016-08-24 10:12

相关推荐

  • 马哥网络班21期-第六周作业

    请详细总结vim编辑器的使用并完成以下练习题    vim(visual interface):文本编辑器      模式        编辑模式        输入模式        末行…

    Linux干货 2016-09-07
  • RPM的使用

    概述 RPM 是 Red Hat PackageManager 的缩写,本意是Red Hat 软件包管理,顾名思义是Red Hat 贡献出来的软件包管理;在Fedora 、Redhat、Mandriva、SuSE、YellowDog等主流发行版本,以及在这些版本基础上二次开发出来的发行版采用; RPM包里面都包含什么?里面包含可执行的二进制程序,这个程序和W…

    Linux干货 2016-02-14
  • Linux基础知识之磁盘及文件系统管理(二)

    1.磁盘和文件系统管理: 文件系统管理工具:     创建文件系统工具(文件系统建议使用ext4)     (1)mkfs.FS_TYPE         a.mkfs.{ext2,ext3,ext4…

    Linux干货 2016-08-29
  • Linux文件系统初识

    Linux文件系统初识        文件系统是一种用于向用户提供数据访问的机制,我们的硬盘,U盘等存储设备会被文件系统分割为特定大小的块,系统中的文件就被存储在数据块中,而我们平常接触到的分区,目录,文件等正是文件系统通过组织整合之后才呈现在我们面前的,我们无需去关心我们的数据到底存储在硬盘的那个…

    2017-07-15
  • N29 第一周作业

    1、描述计算机的组成及其功能。
    2、按系列罗列Linux的发行版,并描述不同发行版之间的联系与区别。
    3、描述Linux的哲学思想,并按照自己的理解对其进行解释性描述。
    4、说明Linux系统上命令的使用格式;详细介绍ifconfig、echo、tty、startx、export、pwd、history、shutdown、poweroff、reboot、hwclock、date命令的使用,并配合相应的示例来阐述。
    5、如何在Linux系统上获取命令的帮助信息,请详细列出,并描述man文档的章节是如何划分的。
    6、请罗列Linux发行版的基础目录名称命名法则及功用规定

    Linux干货 2018-03-05
  • 网卡别名与bonding

    网络接口配置-bonding Bonding简介 Bonding 就是将多块网卡绑定同一IP地址对外提供服务,可以实现高 可用或者负载均衡。然,直接给两块网卡设置同一IP地址 是不可能的。通过bonding,虚拟一块网卡对外提供连接, 物理网卡的被修改为相同的MAC地址。 Bonding模式 Mode 0 (balance-rr) 轮转(Round-robi…

    Linux干货 2016-09-05