shell训练营 | 3. Shell 的函数、模块化、公共函数库

972 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情

王志远,微医前端技术部

Shell 的函数、模块化、公共函数库

shell 之函数

用于重复命令逻辑的集合

  • 函数的定义和执行
  • 函数参数
  • 函数的作用范围
  • 模块化
  • 系统自建函数库

函数的定义和执行

定义

# function 关键词可以省略
function fname(){
 命令
}

执行

fname

实例

# function 关键词可以省略
function cdls() {
    cd /var
    ls
}
cdls

函数变量

分为内部定义的变量和外部的传参

内部定义
local 变量名
外部传参

调用

funcName a b

这里有巨坑:

  1. 函数的返回值(return)只支持数字类型,所以我们需要使用 echo 输出流的形式巧妙的模拟返回其他类型数据
function funcName(){
	echo aaa
}
returnContent=`funcName`
  1. 如果参数中包含了空格,一定要在传递时用引号包裹,不然会被解析成多个参数(比如数组)
arr=(a b c)
funcName "${arr[@]}"
  1. 参数和返回值只支持字符串,所以如果想支持数组,可以采用如下方式:
    1. 入参:将数组的所有内容转为字符串传递,再在内部转为数组
    2. 返回值:将数组的所有内容转为字符串返回,再在外部转为数组
<<'COMMENT'
追加元素
@param arr 数组名
@param item 被追加的元素
@return  改变后的数组字符串
COMMENT

function push() {
    # 获取数组名
    local name=$1
    # 获取数组内容,创造一个对应的内部数组
    eval local innerArr=(\${${name}[@]})
    local item=$2
    innerArr+=($item)
    # 先清除的尝试 失败
    # local length=${#innerArr[@]}
    # eval unset $name 
    # for((i=0;i<$length;i++)); do
    #     eval unset $name[$i]
    # done
    echo ${innerArr[@]}
}
arr=(a b c)
arr=(`push arr aaa`) # 这里的数组已经成为(a b c d)
echo arr===${arr[@]}
内部使用
$1 $2 $3...$n

注意点

  1. 如果两位数了,假如是 10,就需要使用${10}
  2. $#:参数个数总数
  3. $*:作为字符串输出所有参数
  4. @:与@:与*相同,但是使用时加引号,并在引号中返回每个参数
funWithParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
实例之传参
# function 关键词可以省略
function cdls() {
    cd $1
    ls
}
cdls /tmp
实例之内部变量
# function 关键词可以省略
function checkpid() {
    local i
    for i in $*; do
        # linux 中,每个在运行的进程都会有一个在/proc 目录下对应的子目录,目录名为 pid,这也是 ps
        [ -d "/proc/$i" ] && return 0
    done
}
checkpid 5380
echo $?

模块化

其实 shell 的模块化(即函数的导入导出)非常简单,我们知道 shell 会话间的变量是互通的(函数中的 local 变量除外),这时我们只要以当前 shell 会话执行下定义函数的 sh,就能访问到对应的函数了。而如何以当前 shell 执行呢?就是之前讲到的知识:以 source 或者.方式执行 sh 文件。

引入

引入方式很简单

source [函数库的绝对路径]
./11.sh
source 11.sh

bash 11.sh
~ 11.sh

sh
bash
案例

存在函数库 libs/os.sh

#!/bin/bash
# 获取当前系统类型
# @return  platForm
function getPlatForm() {
    local innerPlatForm
    if [[ $(uname) == 'Darwin' ]]; then
        innerPlatForm=mac
    fi
    if [[ $(uname) == 'Linux' ]]; then
        innerPlatForm=linux
    fi
    if [[ $(uname) == 'win32' ]]; then
        innerPlatForm=window
    fi
    # shell 的 function 只能返回整数值,所以如果想接收字符串类型 echo+$()方式获取
    echo $innerPlatForm
}

引入使用时

source ./libs/os.sh
# 执行函数
platForm=$(getPlatForm)
# 看输出结果
echo $platForm
注意事项
  1. shell 的 function 中的 return 语句只能返回整数值,所以如果想接收字符串类型 echo+$()方式获取

系统自建函数库

linux 系统中存在自带的函数库,地址如下

/etc/init.d/functions

在配置文件中也是用了大量的循环判断,可以看/etc/profile或者/etc/.bashrc