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

相关推荐

  • 胡说八道计算机网络之什么是网络(一)?

    胡说八道计算机网络之什么是网络(一) 什么是网络? 网络通信的实现:tcp/ip协议 使用Wireshark抓包分析tcp/ip协议栈 什么是网络?      所谓网络,就是通过一定的形式连接起来的物体,物体与物体之间可以实现通信。     比如这样的,就称为计算机网络。它可以实现计算机之…

    Linux干货 2017-05-01
  • iptables/netfilter进阶

      在上一章当中我们介绍了iptables的介绍以及它的基本使用,下面我们开始介绍iptables的命令用法以及iptables是如何工作的。 1、回顾 2、iptables相关命令 1、回顾   我们回顾一下上一章节的内容,在上一章节中我们讲述的是iptables的基本概念以及命令格式,同时讲述规则链与表的概念,那么…

    Linux干货 2017-02-03
  • Linux中的网络管理

    1. ifconfig命令的使用方法 ifconfig是一个比较老的命令了,以后可能会慢慢被ip命令替代。ifconfig命令可以用来配置网卡ip地址,配置网卡别名等信息。 ifconfig ifconfig 网络设备名:用来查看网卡的信息,如ip地址,子网掩码,MAC地址等信息 ifconfig eth0 add 172.16.0.35/16:配置eth0…

    2017-05-02
  • 文本处理工具-习题

    1 、找出ifconfig 命令结果中本机的所有IPv4地址 [root@centos7 ~]# ifconfig |head -2 |tail-1 |cut -dn -f2 |cut -d" " -f2 2 、查出分区空间使用率的最大百分比值 [root@centos7 ~]# df |cut -c44-46 |sort -n|tail…

    Linux干货 2016-08-15
  • 马哥教育网络班第21期+第四周课程作业

    1. 复制/etc/skel目录为/home/tuser1,要求/home/tuser1及其内部文件的属组和其它用户均没有任何访问权限。 cp -r /etc/skel /home/tuser1 chmod –R 700 /home/tuser1 2. 编辑/etc/group文件,添加组hadoop。 echo &q…

    Linux干货 2016-08-01