Shell 编程快速入门 之 函数基础知识

简介: Shell 编程快速入门 之 函数基础知识

shell函数基础知识

函数定义

函数名

Shell函数用关键字 function 声明,跟在后面的 name 即函数名。声明后就用"函数名 [参数]"来调用函数。function 非必须,也能用函数名加一对括号 name() { ... } 来声明定义函数。

函数体

函数名后的 { Commands; } 即函数体,是实现函数功能的主体。

参数

Shell函数可以通过参数接收输入的值。在函数定义时,可以在括号中指定参数列表。参数可以在函数体中使用,也可以通过特殊变量#获取函数的参数个数,通过特殊变量#获取函数的参数个数,通过特殊变量#获取函数的参数个数,通过特殊变量@获取所有的参数。

返回值

Shell函数可以有一个返回值,可以使用return语句返回一个值。返回值的范围是0到255之间,0表示成功,非零值表示错误。如果函数中没有return语句,或者使用exit命令退出函数,则函数的返回值为退出命令的返回值。

如一个计算2数之和的函数:

#!/bin/bash
function add() {
  local a=$1
  local b=$2
  local res=$((a + b))
  return $res
}
add 3 5
result=$?
echo "The result is: $result"

return返回值的含义

最后结果是从?获取的,其实?获取的,其实?与其它语言中函数返回值是有区别 ,$? 本质上是返回上一条命令的退出状态,并且只是0~255间的整数,也就是最多返回256种状态。

除了$?还有另外4个特殊的变量,它们分别表示以下含义:

  • $$:表示当前Shell进程的进程ID(PID)。
  • $#:表示传递给脚本或函数的参数个数。
  • $@:表示以空格分隔的所有参数,将所有参数视为单个字符串。
  • $*:表示所有参数作为单独的字符串展开,每个参数之间用一个空格分隔。

例程:

hann@HannYang:~$ more sum3.sh
#!/bin/bash
function special_vars() {
  echo "Current PID \$: $$"
  echo "Number of arguments #: $#"
  echo "All arguments (as a single string) @: $@"
  echo "All arguments separated by spaces *: $*"
  echo
  return $(($1+$2+$3))
}
special_vars 1 2 3 4 5
echo "? = "$?
echo "\$ = "$$
echo "# = "$#
echo "@ = "$@
echo "* = "$*
hann@HannYang:~$ bash sum3.sh
Current PID $: 1679
Number of arguments #: 5
All arguments (as a single string) @: 1 2 3 4 5
All arguments separated by spaces *: 1 2 3 4 5
? = 6
$ = 1679
# = 0
@ =
* =

?只能函数执行后调用,?只能函数执行后调用,#,@,@,*只能在函数内部调用,$$则在函数内外都能调用。

return与echo返回值的区别

为了显示两者的不通,echo后加了“sum=”,而return只能返回整数0~255。

例程:

#!/bin/bash
function add() {
  local a=$1
  local b=$2
  local res=$((a + b))
  echo sum=$res
  return $res
}
Result=$(add 100 155)
echo "The result is: $?"
echo "The result is: $Result"
Result=$(add 100 156)
echo "The result is: $?"
echo "The result is: $Result"
Result=$(add 155 358)
echo "The result is: $?"
echo "The result is: $Result"
echo "The result is: $(( (155+358)%256 ))"

输出:

The result is: 255

The result is: sum=255

The result is: 0

The result is: sum=256

The result is: 1

The result is: sum=513

The result is: 1

注意:

return 返回表达式的值,如溢出范围可以认为是 表达式与256相余的结果。

所以shell函多用echo来返回一个字串结果$res再进行调用,而return一般不会作函数值返回语句,它的真实用途是来返回程序运行状态的,比如:

例1:

hann@HannYang:~$ cat test.sh
#!/bin/bash
function filecount {
    # 检查目录是否存在
    if [ -d "$1" ]; then
        # 目录存在,计算文件数
        echo $(ls -l "$1" | grep "^-" | wc -l)
        return 1
    else
        # 目录不存在,返回0
        return 0
    fi
}
dir="$1"
count=$(filecount $dir)
if [ $? = 1 ]
then
    echo "Dir $dir exists,files:$count"
else
    echo "Dir $dir does'nt exist."
fi
dir="$2"
count=$(filecount $dir)
if [ $? = 0 ]
then
    echo "Dir $dir does'nt exist."
else
    echo "Dir $dir exists,files:$count"
fi
hann@HannYang:~$ bash test.sh rust golang
Dir rust exists,files:4
Dir golang does'nt exist.

例2:

hann@HannYang:~$ cat chkpid.sh
checkpid()
{
   #定义本地变量i
    local i
   #使用for循环遍历传递给此函数的所有参数
    for i in $*
    do
       #如果目录/proc/$i存在,则执行此函数返回0
       #在一般的Linux系统中,如果进程正在运行,则在/proc目录下会存在一个以进程号命名的子目录
       [ -d "/proc/$i" ] && return 0
    done
    #返回1
    return 1
}
#调用函数checkpid
checkpid $1 $2 $3
if [ $? = 0 ]
then
    echo "The one of them is running."
else
    echo "These PIDS are not running!"
fi
hann@HannYang:~$ bash chkpid.sh 866
The one of them is running.
hann@HannYang:~$ bash chkpid.sh 866 867 1882
The one of them is running.
hann@HannYang:~$ bash chkpid.sh 1882
These PIDS are not running!
hann@HannYang:~$ bash chkpid.sh 868 1882
These PIDS are not running!

例3:

hann@HannYang:~$ cat prime.sh
#!/bin/bash
is_prime() {
    local num=$1
        if [ $num -lt 2 ]; then
        return 1
    fi
    for ((i=2; i*i<=num; i++)); do
        if [ $((num % i)) -eq 0 ]; then
            return 1
        fi
    done
    return 0
}
for ((i=1;i<12;i++)); do
        if `is_prime $i`; then
                echo "$i 是质数"
        else
                echo "$i 不是质数"
        fi
done
hann@HannYang:~$ bash prime.sh

输出结果:

1 不是质数

2 是质数

3 是质数

4 不是质数

5 是质数

6 不是质数

7 是质数

8 不是质数

9 不是质数

10 不是质数

11 是质数


可变参数函数

"@"的应用:in@"的应用: in @表示遍历所有参数组成的“可迭代数组”。

示例:

#!/bin/bash
# 定义可变参数的函数
function sum4() {
  local sum=0
  for arg in "$@"
  do
    sum=$((sum + arg))
  done
  echo "The sum is: $sum"
}
# 调用函数并传递参数
sum4 10 20 30 50
sum4 1 2 3 4 5 6

输出:

The sum is: 110

The sum is: 21


自定义库函数

定义库函数

例:写一个函数库,如命名为 math_fun.sh

function add
{
    echo "`expr $1 + $2`"
}
function sub
{
    echo "`expr $1 - $2`"
}
function mul
{
    echo "`expr $1 \* $2`"
}
function div
{
    if [ $2 = 0 ]; then
        return 0
    else
        echo "`expr $1 / $2`"
        return 1
    fi
}

调用库函数

在调用库文件的函数时,使用点符号“ . ” + 库函数文件名(指明文件的绝对路径、相对路径都行)进行调用。如 test_fun.sh :

#!/bin/bash
. math_fun.sh
add 10 20
sub 90 100
mul 5 6
div 100 25
div 0 100
div 100 0
if [ $? = 0 ];then
    echo "Error: divide by zero."
fi

执行结果

hann@HannYang:~$ bash test_fun.sh

30

-10

30

4

0

Error: divide by zero.


递归函数

递归函数是一种在程序中调用自身的函数。在 Shell 编程中,也能使用递归函数来解决一些问题,例如计算阶乘、斐波那契数列等。

递归函数的实现需要满足以下两个条件:

  1. 函数必须有一个终止条件,否则会无限循环下去。
  2. 函数必须能够将问题分解成更小的问题,并且能够通过调用自身来解决这些小问题。

阶乘函数

#!/bin/bash
factorial() {
    if [ $1 -le 1 ]
    then
        echo 1
    else
        echo $(( $1 * $(factorial $(( $1 - 1 ))) ))
    fi
}
read -p "请输入一个整数:" num
result=$(factorial $num)
echo "$num 的阶乘为 $result"

改用循环实现:

#!/bin/bash
factorial() {
    local result=1
    for ((i=1; i<=$1; i++))
    do
        result=$((result * i))
    done
    echo $result
}
read -p "请输入一个整数:" num
result=$(factorial $num)
echo "$num 的阶乘为 $result"

斐波那契函数

#!/bin/bash  
fibonacci() {  
    if [ $1 -eq 1 ] || [ $1 -eq 2 ]; then  
        echo 1  
    else  
        echo $(( $(fibonacci $(( $1 - 1 ))) + $(fibonacci $(( $1 - 2 ))) ))  
    fi  
}  
for (( i=1; i<=10; i++)); do  
    echo `fibonacci $i`" "
done

输出:

1 1 2 3 5 8 13 21 34 55  

改用循环实现:

#!/bin/bash
fibonacci() {
    if [ $1 -eq 1 ] || [ $1 -eq 2 ]; then
        echo 1
    else
        a=1
        b=1
        for ((i=3;i<=$1;i++)); do
            c=$((a+b))
            a=$b
            b=$c
        done
        echo $c
    fi
}
for ((i=1;i<=10;i++)); do
    echo -n `fibonacci $i`" "
done

目录
相关文章
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
3月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
1月前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
2月前
|
Shell Linux C语言
Shell 函数
10月更文挑战第4天
22 7
|
2月前
|
Shell
Shell编程(下)
Shell编程(下)
95 1
|
2月前
|
Shell Linux Windows
Shell编程(上)
Shell编程(上)
42 1
|
2月前
|
Shell Linux 开发工具
|
2月前
|
监控 Unix Shell
shell脚本编程学习
【10月更文挑战第1天】shell脚本编程
71 12
|
3月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
3月前
|
存储 Unix Shell
shell脚本编程基础
【9月更文挑战第4天】
46 12