函数

一 函数介绍

什么是函数???

函数就是用来盛放一组代码的容器,函数内的一组代码完成一个特定的功能,称之为一组代码块,调用函数便可触发函数内代码块的运行,这可以实现代码的复用,所以函数又可以称之为一个工具

为何要用函数

#1、减少代码冗余
#2、提升代码的组织结构性、可读性
#3、增强扩展性

二 函数的基本使用

具备某一功能的工具=>函数
事先准备好哦工具=>函数的定义
遇到应用场景,拿来就用=>函数的调用

所以函数的使用原则:先定义,后调用

定义函数

#语法:
[ function ] funname [()]
{
命令1;
命令2;
命令3;

[return int;]
}

示例1:完整写法
function 函数名() {
函数要实现的功能代码
}

示例2:省略关键字(),注意此时不能省略关键字function
function 函数名 {
函数要实现的功能代码
}

示例3:省略关键字function
函数名() {
函数要实现的功能代码
}

示例
#!/bin/bash
function f1() {
    echo "函数1=======》"
}
function f2 {
    echo "函数2=======》"
}
f3() {
    echo "函数3=======》"
}
f1
f2
f3

三 函数参数

f1 #无参调用
f2 11 22 33 44 55 66 #有参调用

示例— 》调用参数
#!/bin/bash

function f1() {
    echo $1
    echo $2
    echo $3
    echo $4
    echo $5
    echo $6
    echo $*
    echo $@

}
f1 11 22 33 44 55 66

#####=======
./function1.sh 
11
22
33
44
55
66
11 22 33 44 55 66
11 22 33 44 55 66

示例—>调用两数相加的函数
#!/bin/bash

function f1() {
    echo $1
    echo $2
    echo $3
    echo $4
    echo $5
    echo $6
    echo $*
    echo $@

}
function add(){
    expr $1 + $2
}
#f1 11 22 33 44 55 66 
add 10 20
add 30 40
add 70 30

######=========
./function1.sh 
30
70
100

ps:在脚本内获取脚本调用者在命令行里为脚本传入的参数,同样使用的是$n,不要搞混
function test1(){
    echo "...start..."
    echo "这是函数内:$1"
    echo "这是函数内:$2"
    echo "这是函数内:$3"
    echo "...end..."
}

test1

echo "这是脚本级的参数$1"
echo "这是脚本级的参数$2"
echo "这是脚本级的参数$3" 
./b.sh xxx yyy zzz mmm nnn
...start...
这是函数内:
这是函数内:
这是函数内:
...end...
这是脚本级的参数xxx
这是脚本级的参数yyy
这是脚本级的参数zzz

四 函数的返回值

如果把函数当成一座工厂,函数的返回值就是工厂的产品,在函数内使用return关键字返回值,函数内可以有多个return,但只要执行一个,整个函数就会立刻结束

#!/bin/bash

function f1(){
    echo 1111
    return
    echo 2222
    return
    echo 3333
}

f1

####=======
./function3.sh 
1111

函数内可以有多个return但是只要执行一个,整个函数就会立刻结束,并且将return后的值当作本次调用的返回值返回
#!/bin/bash

function f1(){
    echo 1111
    while :
    do
        return
    done
    echo 2222
    return
    echo 3333
}

f1
~    
####=======
./function3.sh 
1111


需要注意的是shell语言的函数中,通常用return返回函数运行是否成功的状态,0代表成功,非零代表失败,需要用$?获取函数的返回值
1、如果函数内有return,那么return后跟的只能是整型值并且范围为0-255,用于标识函数的运行结果是否正确, 与C 语言不同,shell 语言中 0 代表 true,0 以外的值代表 false
#!/bin/bash

function f1(){
    echo 1111
    return 0
    echo 2222
    return
    echo 3333
}

f1
echo $?   ####取return返回的结果
~     
####======
./function3.sh 
1111
0  
2.如果函数内没有return,那么将以最后一条命令运行结果(命令运行成功结果为0,否则为非0)作为返回值
#!/bin/bash

function f1(){
    echo 1111
    echo 2222
    asfasgagecho 3333
}

f1
echo $?

#####=====
./function3.sh 
1111
2222
./function3.sh:行6: asfasgagecho: 未找到命令
127

温故知新

参数处理说明
$#传递到脚本或函数的参数个数
$*所有参数
$@所有参数,与$*类似
$$当前脚本进程的ID号
$?获取上一条命令执行完毕后的退出状态。0表示正确,非0代表错误,如果执行的是函数那么$?取的是函数体内return后的值

ps:

#1、当$*和$@没有被引号引用起来的时候,它们确实没有什么区别,都会把位置参数当成一个个体。

#2、"$*" 会把所有位置参数当成一个整体(或者说当成一个单词),如果没有位置参数,则"$*"为空,如果有两个位置参数并且分隔符为空格时,"$*"相当于"$1 $2"

#3、"$@"  会把所有位置参数当成一个单独的字段,如果没有位置参数,则"$@"展开为空(不是空字符串,而是空列表),如果存在一个位置参数,则"$@"相当于"$1",如果有两个参数,则"$@"相当于"$1"  "$2"等等
示例
[root@egon ~]# cat b.sh 
echo "=======函数test1==========="
function test1(){
    echo "$*"  # 111 222 333 444 555
    echo "$@"  # 111 222 333 444 555
    echo $#    # 5
    echo $$    # 87380
    echo $?    # 0
}

test1 111 222 333 444 555


echo "=======函数test2==========="
function test2(){
    for i in "$*"  # 注意:$*不加引号结果与$@一模一样
    do
        echo $i
    done
}

test2 111 222 333 "444 555"  # 注意"444 555"被引号引成了一个参数
# 运行结果为:111 222 333 444 555

echo "=======函数test3==========="
function test3(){
    for i in "$@"  # 注意:$*不加引号结果与$@一模一样
    do
        echo $i
    done
}

test3 111 222 333 "444 555"  # 注意"444 555"被引号引成了一个参数
# 运行结果为:
# 111
# 222
# 333
# 444 555

五 变量的作用域

1、局部变量:只能在函数内访问
使用local关键字定义在函数内的变量属于局部范围,只能在函数内使用,如下所示

#!/bin/bash
# 定义函数
function test(){
    local x=111
    echo "函数内访问x:$x"
}
# 调用函数
test
echo "在函数外即全局访问x:$x"  # 无法访问函数内的局部变量
######========
./hello.sh 
函数内访问x:111
在函数外即全局访问x:

2、全局变量:可以在当前shell进程中使用

所谓全局变量,就是指变量在当前的整个 Shell 进程中都有效。每个 Shell 进程都有自己的作用域,彼此之间互不影响。在 Shell 中定义的变量,默认就都是全局变量。

#!/bin/bash

# 全局作用域:在函数外定义都属于全局作用域
y=888888
echo $y

function test(){
    local x=1
    echo "在函数内访问: $x"
}
#test

#echo "在函数外访问: $x "
~                          
#####执行结果
[root@localhost nginx-1.18.0]# chmod +x function4.sh 
[root@localhost nginx-1.18.0]# ./function4.sh 
888888
[root@localhost nginx-1.18.0]# echo $y

[root@localhost nginx-1.18.0]# . function4.sh 
888888
[root@localhost nginx-1.18.0]# echo $y
888888
[root@localhost nginx-1.18.0]# 

1、在函数内定义的变量,如果没有用local声明,那么默认也是全局变量,shell变量语法的该特性与js的变量是类似的(在js函数内部定义的变量,默认也是全局变量,除非加上关键字var)
[root@localhost shell]# cat hello.sh 
#!/bin/bash
function test(){
    x=2222  # 全局变量
}
test
echo "在函数外即全局访问x:$x"  

[root@localhost shell]# ./hello.sh 
在函数外即全局访问x:2222
2、每执行一个解释器,都会开启一个解释的shell进程,每个shell进程都有自己的作用域彼此互不干扰
[root@localhost shell]# x=111  # 该变量仅仅只在当前shell进程中有效,对新的shell进程无影响
[root@localhost shell]# echo $x
111
[root@localhost shell]# bash  # 执行bash解释器,则开启一个新的进程,或者干脆直接打开一个新的终端
[root@localhost shell]# echo $x

[root@localhost shell]# 
3 、全局变量的作用范围是当前的 Shell 进程,而不是当前的 Shell 脚本文件,它们是不同的概念。打开一个 Shell 窗口就创建了一个 Shell 进程,打开多个 Shell 窗口就创建了多个 Shell 进程,每个 Shell 进程都是独立的,拥有不同的进程 ID。在一个 Shell 进程中可以使用 source 命令执行多个 Shell 脚本文件,此时全局变量在这些脚本文件中都有效。
[root@localhost shell]# echo $x

[root@localhost shell]# cat hello.sh 
#!/bin/bash
function test(){
    x=2222  # 全局变量
}
test

[root@localhost shell]# source hello.sh  # 在当前shell进程中执行,产生一个全局变量x
[root@localhost shell]# echo $x  # 在当前shell进程中访问全局变量x,可以看到
2222
[root@localhost shell]# 
[root@localhost shell]# 
[root@localhost shell]# cat aaa.sh 
#!/bin/bash
echo $x

[root@localhost shell]# source aaa.sh # 在当前shell进程中访问全局变量x,同样可以看到
2222

结论:函数test内的全局变量x早已超越了文件,即全局变量是超越文件的,作用范围是整个当前bash进程

串起来示例
#!/bin/bash
y=666666666666

function test(){
    local y=4444444
    echo $y
}
test

echo "===========$y"


#######======
[root@localhost nginx-1.18.0]# chmod +x function3.sh 
[root@localhost nginx-1.18.0]# ./function3.sh 
666666666666
[root@localhost nginx-1.18.0]# vim function3.sh
[root@localhost nginx-1.18.0]# ./function3.sh 
4444444
[root@localhost nginx-1.18.0]# vim function3.sh
[root@localhost nginx-1.18.0]# ./function3.sh 
4444444
===========666666666666

总结

1.局部变量:只能在函数里面看见
2.全局变量:只能在当前shell进程里面看见,但是在子shell里面看不见,想要看见需要在export一下

示例
[root@localhost ~]# x=00000000
[root@localhost ~]# echo $x
00000000
[root@localhost ~]# bash
[root@localhost ~]# echo $x

[root@localhost ~]# exit
exit
[root@localhost ~]# export x
[root@localhost ~]# bash
[root@localhost ~]# echo $x
00000000
[root@localhost ~]# bash
[root@localhost ~]# echo #x

[root@localhost ~]# echo $x
00000000
[root@localhost ~]# ps -ef|grep bash
root       1697   1693  0 10:06 pts/0    00:00:00 -bash
root       1908   1904  0 10:43 pts/1    00:00:00 -bash
root       2041   1697  0 11:28 pts/0    00:00:00 bash
root       2104   2041  0 11:30 pts/0    00:00:00 bash
root       2139   2104  0 11:30 pts/0    00:00:00 bash
root       2169   2139  0 11:30 pts/0    00:00:00 grep --color=auto bash

3、环境变量:在当前进程的子进程中都可以使用

1)全局变量只在当前 Shell 进程中有效,对其它 Shell 进程和子进程都无效。如果使用**export**命令将全局变量导出,那么它就在所有的子进程中也有效了,这称为“环境变量”。
2)所以说环境变量也是临时的,如果想设置成永久的,需要将变量写入shell配置文件中才可以,Shell 进程每次启动时都会执行配置文件中的代码做一些初始化工作,如果将变量放在配置文件中,那么每次启动进程都会定义这个变量。/etc/profile ------->export x=000000 然后source /etc/profile

六 登录shell与非登录shell

  • 1、登录shell:就是通过输入用户名 密码后 或 su - 获得的shell
  • 2、非登录shell:则是通过bash命令和脚本开启的shell环境
  • 3我们知道在linux里一切皆为文件,同样,shell的属性加载也是写到文件里的
    在登陆时就会加载对应文件的内容来初始化shell环境,
    非登录与登录区别就在于加载的文件不同 从而导致获得的shell环境不同
    我们看看登录shell都加载了那些文件
    –> /etc/profile
    –> /etc/profile.d/.sh
    –> $HOME/.bash_profile
    –> $HOME/.bashrc
    –> /etc/bashrc
    再看非登录shell加载的文件,非登录shell加载的文件要少很多
    –> $HOME/.bashrc
    –> /etc/bashrc
    –> /etc/profile.d/
    .sh

通常,我们会将环境变量设置在 $HOME/.bash_profile

但如果不管哪种登录shell都想使用的变量 可以考虑设置在 $HOME/.bashrc或者/etc/bashrc中,因为它们都属于无论如何都会执行的文件,但是,如果我们真的在这类文件中添加了变量,那么意味着每次执行shell都会重新定义一遍该变量,而定义变量是要耗费内存资源的,这非常不可取,所以我们通常会结合export在/etc/profile文件中声明一个全局变量,这样在每次登录用户时产生的顶级shell里会有一个全局变量,所有的子shell都可以看到了,无需重复定义

作业—》写一个计算器

#!/bin/bash

echo "================"
echo "|这是一个计算器|"
echo "|这是一个计算器|"
echo "================"

while true
do
    read -p "请输入第一个整数: " num1
    expr $num1 + 0 &>/dev/null
    if [ $? -eq 0 ];then
        break
    else
        echo "请输入整数"  

    fi
done

while true
do
    read -p "请输入第二个整数: " num2
    expr $num2 + 0 &>/dev/null
    if [ $? -eq 0 ];then
        break
    else
        echo "请输入整数"  

    fi
done

echo"========="
echo "|1.加法|"
echo "|2.减法|"
echo "|3.乘法|"
echo "|4.除法|"
echo "========i"
read -p "请输入序列号: " choice
case $choice in
    1)
        res=`expr $num1 + $num2`
        echo "$num1+$num2=$res"
    ;;
    2)
        res=`expr $num1 - $num2`
        echo "$num1-$num2=$res"
    ;;
    3)
        res=`expr $num1 \* $num2`
        echo "$num1*$num2=$res"
    ;;
    4)
        res=`expr $num1 / $num2`
        echo "$num1/$num2=$res"

    ;;
esac

用select函数优化一下计算器的脚本

#!/bin/bash
echo "================"
echo "|这是一个计算器|"
echo "|这是一个计算器|"
echo "================"

while true
do
    read -p "请输入一个整数: " num1
    expr $num1 + 0 &>/dev/null
    if [ $? -eq 0 ];then
        break
    else
        echo "请输入整数"  

    fi
done

while true
do
    read -p "请输入一个整数: " num2
    expr $num2 + 0 &>/dev/null
    if [ $? -eq 0 ];then
        break
    else
        echo "请输入整数"  

    fi
done

select choice in {"加法","减法","乘法","除法","返回"}
#PS3="请输入序列号"
do
case $choice in
    "加法")
        res=`expr $num1 + $num2`
        echo "$num1+$num2=$res"
    ;;
    "减法")
        res=`expr $num1 - $num2`
        echo "$num1-$num2=$res"
    ;;
    "乘法")
        res=`expr $num1 \* $num2`
        echo "$num1*$num2=$res"
    ;;
    "除法")
        res=`expr $num1 / $num2`
        echo "$num1/$num2=$res"

    ;;
        *)
             break
    ;;
esac
done

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值