Shell中的函数调用

本章学习内容

----------函数介绍

----------函数定义

----------函数使用

----------区分returnexit

----------删除函数

----------注意事项

1、介绍函数  

编写复杂的shell脚本时,完成具体任务的代码可能需要重复使用,此时我们可以将这些代码块剥离出来,并赋予名称,称其为函数。那么,我们在使用这样的代码块时,只需引用该代码块被赋予的函数名称(成为函数调用)。

2、定义函数

<1>俩种方式

▲function fname

{
          command
          command
         }

▲fname

{
          command
          command
         }

<2>函数名不能和命令相同,命令优先级高于函数

<3>函数命名规则

不可与命令相同,否则命令无法正常使用。

函数优先级>命令

不可定义与函数名同名的别名,否则函数无法使用。

别名优先级>函数

所以优先级:别名 >  函数   >  命令

<4>函数中的变量设为局部变量,防止与shell的变量冲突

验证

####创建函数文件fun2,定义test函数
[[email protected] ~]#vim fun2
function test()
{
 a=first
 echo "a=$a"
}
####编写脚本testfun2.sh
[[email protected] ~]#vim testfun2.sh 
#!/bin/bash
#
a=second
source fun2
test
echo "a=$a"
####执行脚本
[[email protected] ~]#bash testfun2.sh 
a=first
a=first

结果表明虽然脚本中定义了a=second,但是执行test函数之后,已经变成了first。为了解决脚本中变量和函数中变量的混淆,一般将函数中的变量定义为局部变量。

3、使用函数

<1>载入函数

子shell中如果需要使用父shell中的函数,需要将函数加载至本shell

加载方式

source FUNCTION

. FUNCTION

注:修改函数之后,必须重新载入shell才能生效

<2>调用函数

输入函数名再加参数即可

4、函数返回值return和exit的不同

return:退出当前函数

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

return 0 :无错误返回。

return 1-255 :有错误返回

exit:退出当前脚本

5、删除函数

unset FUNCTION:删除函数

set:查看所有定义的函数

6、关于函数参数传递问题

不知道大家有没有过这样的疑问,在函数中参数是如何传递的呢?因为在C语言中是这样定义一个函数的:int cmp(int a, int b),变量已经在函数中声明。但是shell中的函数并没有定义参数,这个过程是怎么完成的呢?小编刚开始也很疑惑,后来才明白shell的函数中通过函数位置变量和变量的引用就可以实现参数的传递。下面是一些示例以及传参的注意事项,大家可以参考一下。

####创建函数文件fun1,定义函数add
function add() {
local sum
 sum=$[$1+$2]
 echo $sum
}
####编写脚本testfun1.sh
#!/bin/bash
source fun1
add $1 $2
####执行脚本:
[[email protected] ~/bin]#bash funadd.sh 1 2
3

脚本中的$1和$2是脚本引用命令行的位置变量,而函数中的$1和$2是引用脚本中的第一个变量和第二个变量,我们称其为函数位置变量。(实现传参的方法之一)

看下面这种情况

####创建函数文件fun1,定义函数add
function add() {
local sum
 sum=$[$1+$2]
 echo $sum
}
####编写脚本testfun1.sh
#!/bin/bash
source fun1
read -p "Please input two figures:" a b    #####只添加此行
add $1 $2
####执行脚本
[[email protected] ~/bin]#bash funadd.sh 
Please input two figures:1 2
/root/bin/fun1: line 3: +: syntax error: operand expected (error token is "+")

为什么这里会报错呢?因为在脚本中引用的位置变量$1和$2并不是1和2,也就是说$1和$2并没有值,函数中并没有引用到数值,计算结果当然是错的。从侧面也说明了read是无法引用位置变量的。

那么,该怎么解决呢?答案如下

#!/bin/bash
source fun1
read -p "Please input two figures:" a b
add $a $b
[[email protected] ~/bin]#bash funadd.sh 
Please input two figures:1 2
3

因为此时的$a和$b引用了命令行输入的1和2,而函数中又会调用这俩个值,结果计算正确。

再看一种情况

####创建函数文件fun1,定义函数add
function add() 
{
  local sum
  sum=$[$a+$b]
  echo $sum
}
####编写脚本testfun1.sh
#!/bin/bash
source fun1
add $1 $2   或者   add  $a $b   或者   add
####执行脚本
[[email protected] ~/bin]#bash funadd.sh 
Please input two figures:1 2
3

小编已经实验过,这三种情况都能运行出结果,为了书写简便,都一一列举再在此处。但是大家知道这是为什么吗?因为函数直接引用了命令行的参数(实现传参的方法之二,弱类型编程语言特有的变量引用),也就不需要通过脚本来传参了。所以如果脚本中没有使用$1和$2之类的字符来引用变量,而是直接使用了$a和$b之类的字符,那是此时传参的意义也就不存在了。

再举一个例子加深一下印象

####创建函数文件fun3,定义函数string
function string()
{
if [ $1 == ha ]; then
  echo "nihao"
fi

}
####编写脚本testfun3.sh
#!/bin/bash
#
source fun3
a=ha
string $a
unset a
####执行脚本
[[email protected] ~]#bash testfun3.sh 
nihao
####创建函数文件fun3,定义函数string
function string()
{
if [ $a == ha ]; then
  echo "nihao"
fi

}
####编写脚本testfun3.sh
#!/bin/bash
#
source fun3
a=ha
string $a  或者  string $1  或者  string
unset a
####执行脚本
[[email protected] ~]#bash testfun3.sh 
nihao

课后强化练习

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_NAMEis running...”

如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is stopped...”

其中:SCRIPT_NAME为当前脚本名

####创建函数文件testsrv,定义多个函数
[[email protected] ~/bin/dir]#vim testsrv
function start() {
    if [ -e /var/lock/subsys/testsrv.sh ]; then
      echo "Already start..."
    else
      touch /var/lock/subsys/testsrv.sh
      echo "start ok"
    fi
}

function stop() {
    if [ ! -e /var/lock/subsys/testsrv.sh ]; then
      echo "Already stop..."
    else
      rm -f /var/lock/subsys/testsrv.sh
      echo "stop ok"
    fi
}

function restart() {
    stop stop
    start start
}

function status() {
  if [ -e /var/lock/subsys/testsrv.sh ]; then
    echo "testsrv.sh is running..."
  else
    echo "testsrv.sh is stopped..."
  fi
}

function quit() {
  exit 2
}

function again() {
  while [ $1 != start -a $1 != stop -a $1 != restart -a $1 != status ]; do
  read -p "Error,please enter again:" CHOICE
  done
}    ####最后一个函数未使用,问题。

####编写脚本testsrv3.sh   
source /root/bin/dir/testsrv
cat << EOF
four choices for you:
start)
stop)
restart)
status)
EOF

read -p "please input your choice(start|stop|restart|status|quit):" CHOICE
  while [ $CHOICE != "start" -a $CHOICE != "stop" -a $CHOICE != "restart" -a $CHOICE != "status" ]; do
    read -p "Error,please enter again:" CHOICE
   done
case $CHOICE in 
start)
  start 
  ;;
stop) 
  stop
  ;;
restart) 
  restart 
  ;;
status) 
  status
  ;;
quit)
  quit 
  ;;
esac

或者使用select


####函数不变,改写脚本
#!/bin/bash
source testsrv
PS3="please input your choice:"
select CHOICE in start stop restart status quit; do
  case $CHOICE in
  start)
    start
    ;;
  stop)
    stop 
    ;;
  restart)
    restart 
    ;;
  status)
    status
    ;;
  quit)
    quit 
    ;;
  *)
    echo "Error,please enter again..."
  esac
done

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/ld-linux-x86-64.so.2

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

####创建函数文件copycmd,定义多个函数
function query() {
  ldd /usr/bin/$1
}

function copy() {
  mkdir /mnt/sysroot &> /dev/null
  local dir1
  dir1=/mnt/sysroot
  cp /usr/bin/$1 $dir1
  mkdir /mnt/sysroot/lib64 &> /dev/null
  local dir2
  dir2=/mnt/sysroot/lib64
  cp `ldd /usr/bin/ls | sed -r ‘[email protected][[:space:]]+.*=>?[[:space:]]?(.*)[[:space:]].*@\[email protected]‘` $dir2 &> /dev/null
}

function quit() {
  if [ $1 == quit ]; then
    exit
  fi
}

####编写脚本copycmd4
#!/bin/bash
source copycmd
PS3=‘Please input your option:‘
select option in run quit; do      ####列出俩个选项,是否运行或者退出,select自带循环功能
  case $option in                      退出即可,option是run和quit
  run)
    read -p "Input your cmd:" CMD   ####赋初值,否则无法与quit比较,直接错误                                                       
    until [[ $CMD == quit ]]; do
      if  which $CMD &> /dev/null; then
        query $CMD           ####调用函数
        copy $CMD            ####调用函数
      else
        read -p "Error,again:" CMD  
      fi
    read -p "Input your cmd:" CMD   ####纠正初值,与quit比较
    done
  ;;
  quit)
    quit $option
  ;;
  esac
done
时间: 2024-10-10 14:29:29

Shell中的函数调用的相关文章

Linux Shell 之 Shell中的函数调用

说起函数调用,相信大家也不会陌生,然而对于初学Shell的我来说,Shell中函数调用方式却有点让我不太习惯,自己也走了不少的弯路,因为传递参数时出了一个很"自然"的错误,也让我吃了不少的苦头,所以总结一下Shell中函数的调用方法. 一.Shell中函数的定义 为了方便程序和管理和模块化并减少代码的重复,函数的确是一个好东西.而Shell中函数的定义有两种方法,如下: function fname() { statements: } 或 fname() { statements; }

Shell编程之函数调用

Shell中的函数调用的使用方法见我下面的代码示例: #!/bin/bash # value init ExP="adb shell /data/local/tmp/vpxdec --yv12 --flipuv -t 2 --md5 data/local/tmp/vp9Input/subset_function_test/Boating_1920x1080_t4_yv12_400frames_skip200.webm"; TT="adb shell ls -l /data/l

如何在Shell 中正确的传递函数返回值

Debug 的过成比较无聊,所以这里先上结论和示例,Debug 的笔记看不看并没有什么乱用. 结论 在shell 中使用返回值,唯一具有通用性的方法是使用全局变量,或者使用echo 并在父进程中接收. return 语句不能用来传递计算结果--return 语句是用来传递函数退出状态的,在几乎所有情况下,你的计算结果都不会是退出状态! 任何违反上面规则的shell 脚本,都不具有通用性. 示例 #!/usr/bin/env bash # =============================

shell中if和相关判断符

1. 关于某个档名的『类型』侦测(存在与否),如 test -e filename -e 该『档名』是否存在?(常用) -f 该『档名』是否为档案(file)?(常用) -d 该『文件名』是否为目录(directory)?(常用) -b 该『文件名』是否为一个 block device 装置? -c 该『文件名』是否为一个 character device 装置? -S 该『档名』是否为一个 Socket 档案? -p 该『档名』是否为一个 FIFO (pipe) 档案? -L 该『档名』是否为

linux在shell中获取时间

获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 将当前日期赋值给DATE变量DATE=$(date +%Y%m%d) 有时候我们需要使用今天之前或者往后的日期,这时可以使用date的 -d参数 获取明天的日期 date -d next-day +%Y%m%d 获取昨天的日期 date -d last-day +%Y%m%d 获取上个月的年和月 date -d last-month +%Y%m 获取下个月的年和月date -d next-month +%Y%m 获取明年

在 shell 中使用 vi 模式

作为一名大型开源社区的参与者,更确切地说,作为 Fedora 项目的成员,我有机会与许多人会面并讨论各种有趣的技术主题. 我最喜欢的主题是"命令行"或者说 shell,因为了解人们如何熟练使用 shell 可以让你深入地了解他们的想法,他们喜欢什么样的工作流程,以及某种程度上是什么激发了他们的灵感. 许多开发和运维人员在互联网上公开分享他们的" dot 文件"(他们的 shell 配置文件的常见俚语),这将是一个有趣的协作机会,让每个人都能从对命令行有丰富经验的人中

shell中的重定向(输入输出)

注意:不同版本的Linux会有所区别,不过大同小异 Linux 命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示.一般情况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器. 输出重定向 命令的输出不仅可以是显示器,还可以很容易的转移向到文件,这被称为输出重定向. 命令输出重定向的语法为: $ command > file 这样,输出到显示器的内容就可以被重定向到文件. 例如,下面的命令在显示器上不会看到任何输出: $ who > users 打

书写优雅的shell脚本(五)- shell中(())双括号运算符

在使用shell的逻辑运算符"[]"使用时候,必须保证运算符与算数之间有空格. 四则运算也只能借助:let,expr等命令完成. 今天讲的双括号"(())"结构语句,就是对shell中算数及赋值运算的扩展. 1.语法: ((表达式1,表达式2-)) 2.特点: (1)在双括号结构中,所有表达式可以像c语言一样,如:a++,b--等. (2)在双括号结构中,所有变量可以不加入:"$"符号前缀. (3)双括号可以进行逻辑运算,四则运算 (4)双括号结

[ SHELL编程 ] shell中各种括号的使用方法

转载自:http://www.jb51.net/article/60326.htm 在这里我想说的是几种shell里的小括号,大括号结构和有括号的变量,命令的用法,如下:1.${var} 2.$(cmd) 3.()和{} 4.${var:-string},${var:+string},${var:=string},${var:?string} 5.$((exp)) 6.$(var%pattern),$(var%%pattern),$(var#pattern),$(var##pattern)现在分