跳转到内容

Shell函数定义和调用

课程介绍

函数是编程语言的重要概念,Shell脚本通过函数实现代码复用和模块化。本课程将详细讲解Shell函数的定义、调用、参数传递、返回值等核心概念,帮助你掌握Shell脚本中的函数编程。

1. 函数概述

1.1 什么是函数

函数是一段可重复使用的代码块,可以接受参数并返回结果。

函数的优势

  • 代码复用:避免重复编写相同代码
  • 模块化:将复杂逻辑分解为多个函数
  • 可读性:提高代码可读性
  • 维护性:便于维护和修改

1.2 函数的基本语法

Shell函数有两种定义语法。

语法1:使用function关键字

bash
function 函数名 {
    代码块
}

语法2:不使用function关键字

bash
函数名() {
    代码块
}

2. 函数定义和调用

2.1 定义函数

定义函数的两种方式。

示例1:使用function关键字

bash
#!/bin/bash
# 定义函数
function say_hello {
    echo "Hello, World!"
}

# 调用函数
say_hello

示例2:不使用function关键字

bash
#!/bin/bash
# 定义函数
say_hello() {
    echo "Hello, World!"
}

# 调用函数
say_hello

2.2 调用函数

调用函数非常简单,直接使用函数名即可。

示例

bash
#!/bin/bash
# 定义函数
function greet {
    echo "Hello, $1!"
}

# 调用函数
greet "张三"
greet "李四"

3. 函数参数

3.1 传递参数

函数可以接受参数,使用$1、$2、$3等引用参数。

示例1:传递单个参数

bash
#!/bin/bash
# 定义函数
function greet {
    echo "Hello, $1!"
}

# 调用函数
greet "张三"

示例2:传递多个参数

bash
#!/bin/bash
# 定义函数
function add {
    sum=$(($1 + $2))
    echo "$1 + $2 = $sum"
}

# 调用函数
add 10 20
add 30 40

示例3:传递所有参数

bash
#!/bin/bash
# 定义函数
function print_args {
    echo "参数个数:$#"
    echo "所有参数:$@"
    echo "第一个参数:$1"
    echo "第二个参数:$2"
}

# 调用函数
print_args "张三" "李四" "王五"

3.2 参数引用

函数参数的引用方式。

参数说明
$0函数名
$1~$9第1~9个参数
$#参数个数
$@所有参数(每个参数独立引用)
$*所有参数(作为整体引用)

示例

bash
#!/bin/bash
# 定义函数
function show_params {
    echo "函数名:$0"
    echo "参数个数:$#"
    echo "所有参数($@):$@"
    echo "所有参数($*):$*"
    echo "第一个参数:$1"
    echo "第二个参数:$2"
}

# 调用函数
show_params "张三" "李四" "王五"

4. 函数返回值

4.1 返回状态码

函数可以返回状态码(0-255),0表示成功,非0表示失败。

示例

bash
#!/bin/bash
# 定义函数
function check_file {
    if [ -f "$1" ]; then
        return 0
    else
        return 1
    fi
}

# 调用函数
check_file "/etc/passwd"
echo "返回值:$?"

check_file "/nonexistent"
echo "返回值:$?"

4.2 返回字符串

函数不能直接返回字符串,但可以通过echo输出字符串。

示例1:使用echo返回字符串

bash
#!/bin/bash
# 定义函数
function get_date {
    echo $(date +%Y-%m-%d)
}

# 调用函数
today=$(get_date)
echo "今天是:$today"

示例2:使用变量返回字符串

bash
#!/bin/bash
# 定义函数
function get_date {
    RESULT=$(date +%Y-%m-%d)
}

# 调用函数
get_date
echo "今天是:$RESULT"

5. 函数作用域

5.1 全局变量

全局变量在函数内外都可以访问。

示例

bash
#!/bin/bash
# 定义全局变量
global_var="全局变量"

# 定义函数
function show_var {
    echo "函数内:$global_var"
    global_var="函数内修改"
}

# 调用函数
show_var
echo "函数外:$global_var"

5.2 局部变量

局部变量只在函数内有效,使用local关键字定义。

示例

bash
#!/bin/bash
# 定义全局变量
global_var="全局变量"

# 定义函数
function show_var {
    local local_var="局部变量"
    echo "函数内:$global_var"
    echo "函数内:$local_var"
}

# 调用函数
show_var
echo "函数外:$global_var"
echo "函数外:$local_var"  # 输出为空

6. 函数库

6.1 创建函数库

将常用函数定义在一个文件中,作为函数库。

示例

bash
# 文件:functions.sh

# 函数:检查文件是否存在
function check_file {
    if [ -f "$1" ]; then
        return 0
    else
        return 1
    fi
}

# 函数:检查目录是否存在
function check_dir {
    if [ -d "$1" ]; then
        return 0
    else
        return 1
    fi
}

# 函数:创建备份
function backup_file {
    local file=$1
    local backup="${file}.bak"
    cp "$file" "$backup"
    echo "备份文件:$file -> $backup"
}

6.2 使用函数库

使用source或.命令加载函数库。

示例

bash
#!/bin/bash
# 加载函数库
source ./functions.sh

# 使用函数库中的函数
check_file "/etc/passwd"
if [ $? -eq 0 ]; then
    echo "文件存在"
else
    echo "文件不存在"
fi

backup_file "/etc/passwd"

7. 完整示例

示例1:用户管理函数库

bash
#!/bin/bash
# 用户管理函数库

# 函数:创建用户
function create_user {
    local username=$1
    local password=$2
    
    # 检查用户是否已存在
    if id "$username" &>/dev/null; then
        echo "用户 $username 已存在"
        return 1
    fi
    
    # 创建用户
    useradd "$username"
    
    # 设置密码
    echo "$username:$password" | chpasswd
    
    echo "用户 $username 创建成功"
    return 0
}

# 函数:删除用户
function delete_user {
    local username=$1
    
    # 检查用户是否存在
    if ! id "$username" &>/dev/null; then
        echo "用户 $username 不存在"
        return 1
    fi
    
    # 删除用户
    userdel -r "$username"
    
    echo "用户 $username 删除成功"
    return 0
}

# 函数:查看用户
function show_user {
    local username=$1
    
    # 检查用户是否存在
    if ! id "$username" &>/dev/null; then
        echo "用户 $username 不存在"
        return 1
    fi
    
    # 显示用户信息
    id "$username"
    return 0
}

# 主程序
echo "===== 用户管理 ====="
echo "1. 创建用户"
echo "2. 删除用户"
echo "3. 查看用户"
echo "4. 退出"
echo "=================="

read -p "请选择(1-4):" choice

case $choice in
    1)
        read -p "请输入用户名:" username
        read -s -p "请输入密码:" password
        echo ""
        create_user "$username" "$password"
        ;;
    2)
        read -p "请输入用户名:" username
        delete_user "$username"
        ;;
    3)
        read -p "请输入用户名:" username
        show_user "$username"
        ;;
    4)
        echo "退出"
        exit 0
        ;;
    *)
        echo "选择错误"
        exit 1
        ;;
esac

示例2:文件操作函数库

bash
#!/bin/bash
# 文件操作函数库

# 函数:检查文件是否存在
function check_file {
    if [ -f "$1" ]; then
        return 0
    else
        return 1
    fi
}

# 函数:检查文件权限
function check_permission {
    local file=$1
    local permission=$2
    
    if [ ! -f "$file" ]; then
        echo "文件不存在"
        return 1
    fi
    
    if [ "$permission" = "read" ]; then
        if [ -r "$file" ]; then
            return 0
        else
            return 1
        fi
    elif [ "$permission" = "write" ]; then
        if [ -w "$file" ]; then
            return 0
        else
            return 1
        fi
    elif [ "$permission" = "execute" ]; then
        if [ -x "$file" ]; then
            return 0
        else
            return 1
        fi
    else
        echo "权限类型错误"
        return 1
    fi
}

# 函数:统计文件行数
function count_lines {
    local file=$1
    
    if [ ! -f "$file" ]; then
        echo "文件不存在"
        return 1
    fi
    
    local lines=$(wc -l < "$file")
    echo "文件 $file 的行数:$lines"
    return 0
}

# 函数:搜索文件内容
function search_file {
    local file=$1
    local keyword=$2
    
    if [ ! -f "$file" ]; then
        echo "文件不存在"
        return 1
    fi
    
    local count=$(grep -c "$keyword" "$file")
    echo "文件 $file 中包含 '$keyword' 的行数:$count"
    return 0
}

# 主程序
echo "===== 文件操作 ====="
read -p "请输入文件路径:" file

if ! check_file "$file"; then
    echo "文件不存在"
    exit 1
fi

count_lines "$file"

read -p "请输入搜索关键词:" keyword
search_file "$file" "$keyword"

示例3:系统监控函数库

bash
#!/bin/bash
# 系统监控函数库

# 函数:获取CPU使用率
function get_cpu_usage {
    local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
    echo "CPU使用率:${cpu_usage}%"
}

# 函数:获取内存使用率
function get_mem_usage {
    local mem_usage=$(free | grep Mem | awk '{printf("%.2f", $3/$2 * 100.0)}')
    echo "内存使用率:${mem_usage}%"
}

# 函数:获取磁盘使用率
function get_disk_usage {
    local disk_usage=$(df -h / | tail -1 | awk '{print $5}' | cut -d'%' -f1)
    echo "磁盘使用率:${disk_usage}%"
}

# 函数:获取网络连接数
function get_net_connections {
    local connections=$(ss -an | wc -l)
    echo "网络连接数:$connections"
}

# 主程序
echo "===== 系统监控 ====="
get_cpu_usage
get_mem_usage
get_disk_usage
get_net_connections
echo "=================="

8. 函数最佳实践

8.1 函数命名规范

  • 使用小写字母和下划线
  • 函数名应该描述函数的功能
  • 避免使用Shell关键字

示例

bash
# 好的函数名
check_file()
backup_file()
send_email()

# 不好的函数名
cf()
bf()
se()

8.2 函数注释

为函数添加注释,说明函数的功能、参数、返回值。

示例

bash
# 函数:检查文件是否存在
# 参数:文件路径
# 返回值:0-文件存在,1-文件不存在
function check_file {
    if [ -f "$1" ]; then
        return 0
    else
        return 1
    fi
}

8.3 函数错误处理

为函数添加错误处理,提高脚本的健壮性。

示例

bash
# 函数:创建备份
function backup_file {
    local file=$1
    
    # 检查文件是否存在
    if [ ! -f "$file" ]; then
        echo "错误:文件不存在"
        return 1
    fi
    
    # 创建备份
    local backup="${file}.bak"
    if ! cp "$file" "$backup"; then
        echo "错误:备份失败"
        return 1
    fi
    
    echo "备份成功:$file -> $backup"
    return 0
}

课程总结

这节课我们学习了Shell函数定义和调用。

核心内容:

  • 函数概述
  • 函数定义和调用
  • 函数参数
  • 函数返回值
  • 函数作用域
  • 函数库
  • 完整示例
  • 函数最佳实践

重要概念:

  • 函数定义:function name {} 或 name() {}
  • 函数调用:直接使用函数名
  • 函数参数:$1、$2、$3等
  • 函数返回值:return返回状态码,echo返回字符串
  • 函数作用域:全局变量和局部变量

函数是Shell脚本编程的重要概念,掌握这些知识后,我们将在后续课程中学习文件操作、字符串处理等高级特性。

课后练习

练习1(基础)

创建一个脚本,要求:

  1. 定义一个函数,输出"Hello, World!"
  2. 调用该函数

练习2(进阶)

创建一个脚本,要求:

  1. 定义一个函数,接受两个参数
  2. 计算两个参数的和
  3. 输出结果

练习3(拓展)

创建一个脚本,要求:

  1. 定义一个函数库,包含以下函数:
    • 检查文件是否存在
    • 统计文件行数
    • 搜索文件内容
  2. 使用函数库中的函数

评论区

专业的Linux技术学习平台,从入门到精通的完整学习路径