首页 > 其他分享 >函数

函数

时间:2024-01-24 13:49:38浏览次数:15  
标签:function Shell 函数 示例 echo 全局变量

一、函数的使用

在Shell中,你可以创建和使用函数来封装一系列命令,以便稍后可以多次调用它们。函数可以帮助你使脚本更加模块化和可维护。以下是在Bash shell中创建和使用函数的基本语法:

function function_name {
    # 函数体,包含一系列要执行的命令
    # 可以使用参数 $1, $2, ... 来引用传递给函数的参数
    # 可以使用 return 命令返回一个值(整数)
    # 可以使用 echo 命令输出结果
}

或者,你也可以使用紧凑的语法:

function_name () {
    # 函数体
}

下面是一个示例,展示如何创建一个简单的Shell函数:

#!/bin/bash
​
# 定义一个名为greet的函数,接受一个参数$name
function greet {
    echo "Hello, $1!"
}
​
# 调用函数并传递参数
greet "Alice"  # 输出: Hello, Alice!
greet "Bob"    # 输出: Hello, Bob!

在这个示例中,我们定义了一个名为greet的函数,它接受一个参数$1,然后使用echo命令输出带有参数值的问候语。

你还可以在函数中使用控制流结构(如if语句、for循环等)以及其他Shell命令来执行特定的任务。函数可以在脚本中的任何地方调用,以便在需要时执行相同的操作。函数可以帮助你提高脚本的可读性和可维护性,尤其是对于复杂的脚本或需要重复执行的任务。

二、返回值

在Shell中,命令和函数可以返回一个整数值作为它们的退出状态码(返回值)。通常情况下,0表示成功,而非零值表示失败或出现了错误。这个退出状态码可以在Shell脚本中使用,以便根据命令或函数的执行结果来进行逻辑控制和决策。

以下是有关Shell中的返回值的一些重要概念:

  1. 命令的退出状态码:每个在Shell中运行的命令都会返回一个退出状态码,通常保存在特殊的变量 $? 中。你可以使用 $? 来获取上一个命令的退出状态码。

    示例:

    ls /nonexistent-directory
    if [ $? -ne 0 ]; then
        echo "ls command failed"
    fi
  2. 自定义函数的返回值:在自定义Shell函数中,你可以使用 return 命令来指定函数的返回值。返回值通常是一个整数,表示函数的执行结果。

    示例:

    function add {
        local result=$(( $1 + $2 ))
        return $result
    }
    
    add 5 3
    echo "Sum is: $?"

    在这个示例中,函数 add 计算两个参数的和,并使用 return 返回结果。然后,我们使用 $? 获取函数的返回值。

  3. 使用返回值进行条件判断:你可以使用返回值来进行条件判断,根据命令或函数的成功或失败来执行不同的操作。

    示例:

    rm non-existent-file
    if [ $? -eq 0 ]; then
        echo "File deleted successfully"
    else
        echo "File deletion failed"
    fi

    在这个示例中,我们使用 $? 来检查 rm 命令是否成功删除了文件。

总之,Shell中的返回值是用于表示命令或函数执行结果的一种重要机制。通过检查返回值,你可以编写更健壮的脚本,根据不同情况采取不同的操作。记住,约定俗成的标准是命令成功时返回0,失败时返回非零值,但确切的非零值通常会根据具体情况而有所不同。

三、函数值赋值给变量使用

在Shell脚本中,你可以将函数的返回值赋值给一个变量,然后在脚本的其他地方使用该变量。这可以通过将函数调用作为命令子壳(subshell)来实现,以便捕获函数的输出并将其分配给变量。

以下是一个示例,演示如何将函数的返回值赋值给变量:

#!/bin/bash

# 定义一个名为add的函数,它接受两个参数,并返回它们的和
function add {
    local result=$(( $1 + $2 ))
    echo $result
}

# 调用函数并将返回值赋值给变量
sum=$(add 5 3)

# 输出变量的值
echo "The sum is: $sum"

在这个示例中,我们定义了一个名为add的函数,它接受两个参数并返回它们的和。然后,我们在脚本中调用这个函数,并将其返回值赋值给名为sum的变量。最后,我们使用echo命令输出变量sum的值。

执行脚本后,将看到输出如下:

The sum is: 8

这表明我们成功地将函数的返回值赋值给了变量,并可以在脚本的其他地方使用它。

注意:在将函数的返回值赋值给变量时,函数的标准输出(echo输出)被捕获并存储在变量中。如果函数有多个echo语句,只有最后一个echo的输出会被存储在变量中。如果函数有多个返回值或需要返回复杂的数据结构,可能需要使用其他方法,如将数据写入文件或使用JSON等格式进行交换。

四、函数的传参

在Shell中,你可以将参数传递给函数,以便函数能够接受外部传递的值并在函数内部使用它们。Shell函数使用特殊的变量 $1$2$3 等来引用传递给函数的参数。以下是关于函数传参的一些基本信息:

  • $1:表示传递给函数的第一个参数。

  • $2:表示传递给函数的第二个参数。

  • $3:表示传递给函数的第三个参数。

  • $#:表示传递给函数的参数个数。

  • $*:表示以单个字符串形式返回所有参数。

  • $@:表示以数组形式返回所有参数。

下面是一个示例,演示如何在Shell函数中传递参数:

#!/bin/bash

# 定义一个名为greet的函数,接受一个参数$name
function greet {
    echo "Hello, $1!"
}

# 调用函数并传递参数
greet "Alice"  # 输出: Hello, Alice!
greet "Bob"    # 输出: Hello, Bob!

# 使用特殊变量获取参数个数和所有参数
echo "Number of arguments: $#"
echo "All arguments: $*"

在这个示例中,我们定义了一个名为greet的函数,它接受一个参数$1,然后在函数体中使用$1来引用传递给函数的参数。我们还演示了如何使用特殊变量 $# 来获取参数的个数,并使用 $* 来获取所有参数。

当你调用函数时,可以将多个参数传递给它,函数可以根据需要引用这些参数来执行操作。在复杂的脚本中,函数的参数传递使你能够编写更通用和可重用的代码。

五、函数中的变量

1.全局变量

在Shell脚本中,函数默认情况下是可以访问全局变量的,这意味着函数内部可以读取和修改在函数外部定义的全局变量。这是因为Shell中的变量分为两种范围:

  1. 全局变量(Global Variables):在脚本的任何地方都可以访问的变量,包括函数内部。

  2. 局部变量(Local Variables):只能在定义它们的函数内部访问的变量。

如果你希望在函数内部创建一个全局变量,或者修改一个函数外部的全局变量,可以直接操作全局变量名。不需要使用 local 关键字。

以下是一个示例,演示如何在函数内部访问和修改全局变量:

#!/bin/bash

# 定义一个全局变量
global_variable="I'm a global variable"

# 定义一个函数,访问并修改全局变量
function access_global {
    echo "Inside function: $global_variable"
    global_variable="Modified in function"
}

# 调用函数
access_global

# 打印修改后的全局变量值
echo "Outside function: $global_variable"

在这个示例中,我们定义了一个全局变量 global_variable,然后在函数 access_global 中访问并修改了它。在函数内部和外部都可以看到对全局变量的修改。

虽然函数可以访问全局变量,但要注意,在函数内部如果重新定义了一个同名的局部变量,它会隐藏全局变量,函数将使用局部变量的值而不是全局变量的值。如果你想在函数内部访问全局变量而不隐藏它,请确保不在函数内部重新定义同名的局部变量。

2.局部变量和特殊变量

局部变量在函数内部定义,通常只在函数范围内可见,不会影响到函数外部的变量。这有助于避免命名冲突和保护外部变量的值。以下是如何在Shell函数中处理变量的基本方法:

  1. 创建局部变量:

    在函数内部,你可以使用 local 命令来创建局部变量。局部变量的作用范围仅限于函数内部。

    示例:

    function my_function {
        local var_name="local_variable"
        echo "Inside function: $var_name"
    }
    
    var_name="global_variable"
    my_function
    echo "Outside function: $var_name"

    在这个示例中,函数内部的 var_name 是一个局部变量,不会影响函数外部的 var_name 变量。

  2. 使用参数和特殊变量:

    你可以在函数内部使用参数(如 $1, $2, ...)和特殊变量(如 $#, $*, $@)来处理传递给函数的参数。这允许你在函数中操作参数数据。

    示例:

    function process_data {
        echo "Total number of arguments: $#"
        echo "First argument: $1"
        echo "All arguments: $*"
    }
    
    process_data 1 "two" 3

    在这个示例中,process_data 函数接受多个参数,并使用特殊变量 $#$1$* 来处理它们。

  3. 返回值:

    你可以使用 return 命令来从函数中返回一个值。这个返回值可以是整数,通常用来表示函数的执行状态或结果。

    示例:

    function calculate_sum {
        local result=$(( $1 + $2 ))
        return $result
    }
    
    calculate_sum 5 3
    sum=$?
    echo "The sum is: $sum"

    在这个示例中,calculate_sum 函数计算两个参数的和,并使用 return 返回结果。然后,我们将返回值存储在 sum 变量中。

通过使用局部变量、参数和特殊变量,以及适当的返回值,你可以在Shell函数中有效地处理变量和数据,使函数能够执行各种任务和计算。

3.修改全局变量的值

如果你希望函数内部能够修改全局变量的值,需要使用 declaretypeset 命令将该变量声明为全局变量。例如:

#!/bin/bash

# 定义一个全局变量
global_variable="I'm a global variable"

# 定义一个函数,修改全局变量的值
function modify_global_variable {
    declare -g global_variable="Modified in function"
}

# 调用函数
modify_global_variable

# 打印全局变量的值
echo "Outside function: $global_variable"

在这个示例中,我们使用 declare -g 声明了全局变量,这样函数内部的修改会影响到全局变量的值。因此,最后打印的全局变量值将会是在函数内部修改后的值。

需要小心使用全局变量,确保它们的修改不会导致意外行为或不希望的副作用

4.跨脚本使用函数

在Shell中,要在不同的脚本文件中调用函数,你可以使用一些方法来实现跨脚本调用。这可以通过将函数定义放在一个共享的文件中,然后在需要的脚本中导入该文件来完成。以下是一种常见的方法:

  1. 创建一个包含函数定义的共享文件:

    首先,创建一个包含你要共享的函数定义的文件,例如 shared_functions.sh

    # shared_functions.sh
    
    # 定义一个函数
    function my_function {
        echo "Hello from shared function!"
    }
  2. 在需要调用函数的脚本中导入共享文件:

    在需要使用这些函数的Shell脚本中,使用 source. 命令来导入共享文件。这将使共享文件中的函数在当前脚本中可用。

    # script1.sh
    
    # 导入共享文件
    source shared_functions.sh
    
    # 调用共享函数
    my_function
    # script2.sh
    
    # 导入共享文件
    source shared_functions.sh
    
    # 调用共享函数
    my_function
  3. 运行脚本:

    现在,你可以分别运行 script1.shscript2.sh,它们都将调用共享文件中的 my_function 函数。

通过这种方法,你可以在不同的Shell脚本文件中实现函数的跨脚本调用。请确保共享文件的路径在脚本中正确设置,以便Shell能够找到它。

注意:在使用 source 命令导入文件时,共享文件中的代码将在当前Shell环境中执行,因此函数定义和变量等将在当前Shell中生效。如果你只想将文件中的函数和变量封装在一个子shell中运行,可以考虑使用新的子shell,例如 (source shared_functions.sh)。这将在子shell中执行文件,并在子shell退出后不会影响当前Shell的环境。

4.(){}在跨脚本导入的区别

如果你想在子shell中运行共享文件(如 shared_functions.sh),你可以使用一对小括号 (source shared_functions.sh) 或者 { source shared_functions.sh; },这将在子shell中执行该文件。使用小括号或花括号的区别在于子shell的创建方式:

  1. 小括号 () 使用小括号会创建一个新的子shell,其中的命令会在子shell中执行。当子shell执行完毕后,其环境将被销毁,不会影响当前Shell环境。

    示例:

    (source shared_functions.sh)
  2. 花括号 {} 花括号也可以用来创建一个子shell,但与小括号不同,花括号创建的子shell在当前Shell中运行,而不会启动一个新的Shell进程。花括号内的命令在同一进程中执行,但在一个子shell中,因此它们不会影响当前Shell环境。

    示例:

    { source shared_functions.sh; }

这两种方式都可以用来在子shell中运行共享文件,你可以根据具体需求选择其中一种。一般来说,如果你希望共享文件中的操作不会影响到当前Shell环境,使用小括号更为常见,因为它们会创建一个独立的子shell。

 

六、实战

1、自动备份mysql数据库脚本

1、登录mysql

2、创建数据库和表

[root@fishman-160 ~]# mysql -uroot -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 8
Server version: 10.3.28-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.810 sec)

MariaDB [(none)]> create database xuegod;
Query OK, 1 row affected (0.000 sec)

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| xuegod             |
+--------------------+
4 rows in set (0.001 sec)

MariaDB [(none)]> use xuegod
Database changed
MariaDB [xuegod]> create table user(id int);
Query OK, 0 rows affected (0.006 sec)

MariaDB [xuegod]> insert into user value(1);
Query OK, 1 row affected (0.001 sec)

MariaDB [xuegod]> select * from user;
+------+
| id   |
+------+
|    1 |
+------+
1 row in set (0.000 sec)

MariaDB [xuegod]> insert into user value(2);
Query OK, 1 row affected (0.001 sec)

MariaDB [xuegod]> select * from user;
+------+
| id   |
+------+
|    1 |
|    2 |
+------+
2 rows in set (0.000 sec)

image-20230913125746523

3、脚本

#!/bin/bash
# Auto backup MySQL

# Define variables
BAKDIR="/data/backup/mysql/$(date +%F)"
MYSQLDB="xuegod"
MYSQLUSER="root"
MYSQLPW=''

# Check if the script is running as root
if [ "$EUID" -ne 0 ]; then
    echo "This script must be run as the root user!"
    exit 1
fi

# Create the backup directory if it doesn't exist
if [ ! -d "$BAKDIR" ]; then
    mkdir -p "$BAKDIR"
else
    echo "The directory $BAKDIR already exists."
fi

# Use mysqldump to backup MySQL (no password provided)
mysqldump -u "$MYSQLUSER" -p "$MYSQLDB" > $BAKDIR/${MYSQLDB}_db.sql

# Check if the backup was successful
if [ $? -eq 0 ]; then
    echo "MySQL backup on $(date +%F) was successful!"
else
    echo "MySQL backup on $(date +%F) failed."
fi

# Compress the SQL dump file
cd "$BAKDIR" && tar -zcf "${MYSQLDB}_db.tar.gz" *.sql

# Remove SQL dump files
find "$BAKDIR" -name "*.sql" -type f -delete

# Remove backup directories older than 30 days
find /data/backup/mysql/ -mindepth 1 -type d -mtime +30 -exec rm -rf {} \;

echo "MySQL backup completed successfully."

4、执行脚本

1694584154251

5、查看打包里的文件

1694583353943

2、nginx启动脚本

#!/bin/bash
  2 ### BEGIN INIT INFO
  3 # Provides:          nginx
  4 # Required-Start:    $local_fs $remote_fs $network $syslog
  5 # Required-Stop:     $local_fs $remote_fs $network $syslog
  6 # Default-Start:     2 3 4 5
  7 # Default-Stop:      0 1 6
  8 # Short-Description: Nginx HTTP server
  9 # Description:       Nginx is a high-performance HTTP server.
 10 ### END INIT INFO
 11 
 12 #Nginx installation directory
 13 NGINX_BIN="/usr/local/nginx/sbin/nginx"
 14 
 15 #Nginx configuration file
 16 NGINX_CONF="/usr/local/nginx/conf/nginx.conf"
 17 
 18 #Nginx pid_file
 19 NGINX_PID="/usr/local/nginx/logs/nginx.pid"
 20 
 21 #Function to start Nginx
 22 start(){
 23         echo "Starting Nginx..."
 24         $NGINX_BIN -c $NGINX_CONF
 25 }
 26 
 27 #Function to stop Nginx
 28 stop(){
 29         echo "Stopping Nginx..."
 30         $NGINX_BIN -s stop
 31 }
 32 
 33 #Function to reload Nginx
 34 reload(){
 35         echo "Reloading Nginx confuguration..."
 36         $NGINX_BIN -s reload
 37 }
 38 
 39 #Function to check Nginx
 40 status(){
 41         if [ -f $NGINX_PID ];then
 42                 echo "Nginx is running (PID:$(cat $NGINX_PID))"
 43         else
  44                 echo "Nginx is not running"
 45         fi
 46 }
 47 
 48 #Check if the scprits is run as root
 49 if [ $(id -u) != 0 ];then
 50         echo "This scrpits must be run as root"
 51         exit 1
 52 fi
 53 
 54 #Parse command-line arguemts
 55 case "$1" in
 56         start)
 57                 start
 58                 ;;
 59         stop)
 60                 stop
 61                 ;;
 62         reload)
 63                 reload
 64                 ;;
 65         status)
 66                 status
 67                 ;;
 68         *)
 69                 echo "Usage:$0 (start|stop|reload|status)"
 70                 exit 1
 71                 ;;
 72 esac
 73 
 74 exit 0                                                                            

上述内容保存为一个脚本文件,例如 nginx.sh,然后将其设置为可执行:

chmod +x nginx.sh

然后,你可以使用以下命令来启动、停止、重新加载和查看 Nginx 服务的状态:

# 启动 Nginx
./nginx.sh start
​
# 停止 Nginx
./nginx.sh stop
​
# 重新加载 Nginx 配置
./nginx.sh reload
​
# 查看 Nginx 状态
./nginx.sh status

标签:function,Shell,函数,示例,echo,全局变量
From: https://www.cnblogs.com/kcloveworld/p/17984480

相关文章

  • 子函数对指定文件指的读取指定的行(ReadLine.bat)
    经常要对文件的指定行进行读取,特写了一个读取文件指定行的小程序段(ReadLine.Bat),方面以后调用。使用也比较简单:"CallReadLine<文件名><跳过的行数><读取行数>"就可以了。比如在一个批处理里加上一句"CallReadLinea.txt57",那么将跳过a.txt文件的前5行,显示下面的7行字......
  • C#析构函数解析:资源管理的精要和使用技巧
     在C#中,析构函数(Destructor)是一个特殊的方法,用于清理对象占用的资源。它是由垃圾回收器在对象被销毁时自动调用的。析构函数的原理是在对象即将被回收时执行一些清理操作,例如释放非托管资源或执行一些对象销毁前的必要操作。析构函数的基本原理:调用时机: 当对象被垃圾回收......
  • 函数递归经典题目——汉诺塔,青蛙跳台阶
    函数递归(recursion)函数递归(recursion)程序调用自身的编程技巧。只需要少量程序就可以描述除解题过程所需要的多次重复运算,大大减少了代码量递归---把大事化小必要条件*2 1存在限制条件,当满足这个限制条件时,递归便不再继续 2每次递归调用之后越来越接近这个限制条件递归......
  • java8 函数式(Functional)接口
    什么是函数式(Functional)接口 只包含一个抽象方法的接口,称为函数式接口。 你可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。 我们可以在一个接口上使用@FunctionalInterfa......
  • 大语言模型的架构及其训练(目标函数和优化算法)
    先占坑24号早上起来补大模型的架构 大模型的训练模型训练=目标函数+优化算法可用任何模型将token序列映射到上下文嵌入中一、目标函数1.Decoder-only模型①映射到上下文嵌入②用嵌入矩阵获得每个token得分③指数化、归一化得预测分布用负对数最大似然作为目标函数2.Encoder-o......
  • OCaml入门-值与函数
    Ocaml使用;;来确认一个表达式的结束举例:#50*50;;-:int=2500OCaml告诉我们50*50的结果是int可以用x为常量50*50命名,注意这里x的值不可以被修改#letx=50*50;;-:valx:int=2500使用let...in...来定义局部变量,在下面这个例子中,y=5......
  • ORACLE translate函数
     1.语法  2.用途   (1)translate的返回值,是将expr(源字符串)参数中,所有对应在from_string(源字符串中想要被替换的字符)参数中所出现的字符,均按from_string参数中在to_string(想要源字符串中被替换的对应目标字符)参数中对应的字符替换掉后的值。expre源字符串中有......
  • 走出大模型部署新手村!小明这样用魔搭+函数计算
    作者:拓山前文介绍了魔搭ModelScope社区模型服务SwingDeploy服务。开发者可以将模型从魔搭社区的模型库一键部署至阿里云函数计算,当选择模型并部署时,系统会选择对应的机器配置。按需使用可以在根据工作负载动态的减少资源,节约机器使用成本。5分钟完成从开源模型至模型推理API服......
  • mysql patition by--分区函数
    分区函数patitionbygroupby是分组函数,partitionby是分区函数partitionby并没有groupby的汇总功能。partitionby统计的每一条记录都存在,而groupby将所有的记录汇总成一条记录(类似于distinctEmpDepartment去重)相同点:groupby后的聚合函数,partionby后的orderby......
  • vue-helper 点击跳转插件 在 methods里面互相调用函数,会产生两个函数definitions ,然后
    vue-helper点击跳转插件在methods里面互相调用函数,会产生两个函数definitions,然后就回弹出框让你选择原因:换了台电脑,又从新配置下vscode"editor.gotoLocation.multipleTypeDefinitions":"goto","editor.gotoLocation.multipleReferences":"goto","editor.got......