一、Shell函数

1. 函数的定义与调用

函数定义格式

格式1:标准写法

函数名() {
    命令序列
    [return 返回值]
}

格式2:使用function关键字

bash

function 函数名 {
    命令序列
    [return 返回值]
}
函数调用
# 直接调用
函数名

# 带参数调用
函数名 参数1 参数2
示例1:基础函数
#!/bin/bash
# 定义简单函数

hello() {
    echo "Hello, World!"
}

# 调用函数
hello
示例2:带返回值的函数
#!/bin/bash
# 计算两个数的和

add() {
    local sum=$(( $1 + $2 ))
    echo $sum
    return 0
}

# 调用函数并获取返回值
result=$(add 10 20)
echo "两数之和为: $result"

2. 函数变量的作用范围

全局变量与局部变量
#!/bin/bash
# 演示变量作用范围

# 全局变量
global_var="我是全局变量"

test_scope() {
    # 局部变量
    local local_var="我是局部变量"
    
    echo "函数内部:"
    echo "  - global_var = $global_var"  # 可以访问全局变量
    echo "  - local_var = $local_var"    # 可以访问局部变量
    
    # 修改全局变量
    global_var="全局变量被函数修改"
}

# 调用函数
test_scope

echo "函数外部:"
echo "  - global_var = $global_var"      # 全局变量已被修改
echo "  - local_var = $local_var"        # 无法访问局部变量(输出为空)
示例:变量作用域实战
#!/bin/bash
# 计算器程序

result=0  # 全局变量

add() {
    local a=$1
    local b=$2
    result=$((a + b))  # 修改全局变量
    echo "加法结果(内部): $result"
}

subtract() {
    local a=$1
    local b=$2
    local result=$((a - b))  # 局部变量,不影响全局
    echo "减法结果(内部): $result"
}

add 20 30
echo "加法结果(外部): $result"  # 输出50

subtract 50 30
echo "减法结果(外部): $result"  # 仍然是50,未被修改

3. 函数的参数

参数处理特殊变量
变量 说明
$0 脚本名称
$1$2... 第1个、第2个...参数
$# 参数个数
$* 所有参数(作为一个字符串)
$@ 所有参数(作为多个字符串)
$? 上一个命令的退出状态
示例1:基础参数传递
#!/bin/bash
# 显示函数参数

show_params() {
    echo "函数名称: $0"
    echo "第一个参数: $1"
    echo "第二个参数: $2"
    echo "第三个参数: $3"
    echo "参数总数: $#"
    echo "所有参数(\$*): $*"
    echo "所有参数(\$@): $@"
}

show_params apple banana orange
示例2:参数遍历
#!/bin/bash
# 计算多个数的平均值

average() {
    local sum=0
    local count=$#
    
    # 使用$@遍历所有参数
    for num in $@
    do
        sum=$((sum + num))
    done
    
    echo "总和: $sum"
    echo "个数: $count"
    echo "平均值: $((sum / count))"
}

average 10 20 30 40 50
示例3:带选项的函数
#!/bin/bash
# 带选项的日志函数

log_message() {
    local level="INFO"  # 默认级别
    local message=""
    
    # 解析选项
    while getopts "l:m:" opt
    do
        case $opt in
            l) level="$OPTARG" ;;
            m) message="$OPTARG" ;;
            *) echo "用法: $0 -l [级别] -m [消息]" ;;
        esac
    done
    
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message"
}

# 调用函数
log_message -l "ERROR" -m "文件未找到"
log_message -l "WARNING" -m "磁盘空间不足"
log_message -m "这是一条INFO日志"  # 使用默认级别
示例4:参数默认值
#!/bin/bash
# 设置默认参数

create_user() {
    local username=${1:-guest}  # 如果没有参数,默认为guest
    local home_dir=${2:-/home/$username}
    local shell=${3:-/bin/bash}
    
    echo "创建用户:"
    echo "  用户名: $username"
    echo "  家目录: $home_dir"
    echo "  Shell: $shell"
}

create_user alice
echo "---"
create_user bob /home/bob123 /bin/zsh

4. 递归函数

什么是递归函数?

函数调用自身称为递归,必须有一个终止条件。

示例1:计算阶乘
#!/bin/bash
# 递归计算阶乘

factorial() {
    local num=$1
    
    # 终止条件
    if [ $num -le 1 ]; then
        echo 1
        return 0
    fi
    
    # 递归调用
    local prev=$(factorial $((num - 1)))
    echo $((num * prev))
}

# 测试
result=$(factorial 5)
echo "5的阶乘是: $result"  # 输出120
示例2:斐波那契数列
#!/bin/bash
# 递归计算斐波那契数列

fibonacci() {
    local n=$1
    
    if [ $n -le 1 ]; then
        echo $n
        return 0
    fi
    
    local prev1=$(fibonacci $((n - 1)))
    local prev2=$(fibonacci $((n - 2)))
    echo $((prev1 + prev2))
}

echo "斐波那契数列第10项: $(fibonacci 10)"
示例3:递归遍历目录
#!/bin/bash
# 递归遍历目录并计算文件数量

count_files() {
    local dir=$1
    local count=0
    
    echo "进入目录: $dir"
    
    # 遍历目录中的每个文件/子目录
    for item in "$dir"/*
    do
        if [ -f "$item" ]; then
            # 是普通文件
            count=$((count + 1))
            echo "  文件: $item"
        elif [ -d "$item" ]; then
            # 是子目录,递归调用
            local sub_count=$(count_files "$item")
            count=$((count + sub_count))
        fi
    done
    
    echo "目录 $dir 包含 $count 个文件"
    return $count
}

# 调用函数(需要指定实际存在的目录)
count_files "/etc"
示例4:递归创建目录结构
#!/bin/bash
# 递归创建嵌套目录

create_nested_dirs() {
    local path=$1
    local depth=$2
    
    # 终止条件
    if [ $depth -le 0 ]; then
        return
    fi
    
    # 创建当前目录
    mkdir -p "$path"
    echo "创建目录: $path"
    
    # 递归创建子目录
    create_nested_dirs "$path/level$depth" $((depth - 1))
}

create_nested_dirs "./test_tree" 3
tree ./test_tree  # ;需要tree命令的方式

  local parth-ilem 

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐