shell 中的 set -e , set +e 用法

本文介绍了Shell脚本中set-e选项的作用与使用方法,并通过示例对比了set-e开关前后脚本的行为差异。此外,还讲解了如何利用#!/usr/bin/env指定脚本解释器路径以增强脚本的兼容性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考资料: http://blog.youkuaiyun.com/xiaofei125145/article/details/39345331

Shell -e

set -e # Exit the script if an error happens

#!/bin/bash
set -e  #"Exit immediately if a simple command exits with a non-zero status."
touch a.txt
echo "touch a.txt done"
i   #这里有个错误,马上终止脚本

for i in 1 2 3
do 
    echo "$i" >>a.txt
done
cat a.txt
echo "" > a.txt
echo "Hello World !" 

Shell +e

set +e # don’t bail out of bash script if ccache doesn’t exist

#!/bin/bash
set -e  #"Exit immediately if a simple command exits with a non-zero status."
touch a.txt
echo "touch a.txt done"
i   #这里有个错误,报错但是继续执行下面的脚本

for i in 1 2 3
do 
    echo "$i" >>a.txt
done
cat a.txt
echo "" > a.txt
echo "Hello World !" 

env

http://blog.youkuaiyun.com/u014114990/article/details/47810207

在Linux的一些脚本里,需在开头一行指定脚本的解释程序,如:
#!/usr/bin/env Python
再如:
#!/usr/bin/env perl
#!/usr/bin/env zimbu

但有时候也用
#!/usr/bin/python#!/usr/bin/perl

但有时候也用
#!/usr/bin/python#!/usr/bin/perl

那么 env到底有什么用?何时用这个呢?
脚本用env启动的原因,是因为脚本解释器在linux中可能被安装于不同的目录,env可以在系统的PATH目录中查找。同时,env还规定一些系统环境变量。

而如果直接将解释器路径写死在脚本里,可能在某些系统就会存在找不到解释器的兼容性问题。有时候我们执行一些脚本时就碰到这种情况。


<think>我们注意到查询结果中,元数据中的`mysql_server_uuid`与当前实例的`@@server_uuid`一致,但是元数据中的`group_replication_group_name`(存储在集群的attributes中,这里没有直接显示)与当前实例的`@@group_replication_group_name`不一致。在返回的结果中,我们看到: - `current_gr_name` (当前实例的GR组名): 9f8c6f7e-5652-11f0-a2e0-000c292cd265 - 而元数据中存储的GR组名(通过之前的查询可以知道)可能是另一个值(比如在集群元数据attributes中的group_replication_group_name)。 这解释了为什么恢复失败:因为元数据中记录的GR组名与实际运行的GR组名不一致,导致InnoDB Cluster API无法识别当前实例属于集群。 解决方案: 1. 更新元数据中的GR组名,使其与当前实例的GR组名一致。 2. 如果集群中有多个实例,需要确保所有实例的GR组名一致(通常应该一致,因为GR组名是集群级别的)。 具体步骤: 步骤1:查询当前集群元数据中存储的GR组名(假设集群名为'myCluster'): ```sql SELECT cluster_id, JSON_EXTRACT(attributes, '$.group_replication_group_name') AS stored_gr_name FROM mysql_innodb_cluster_metadata.clusters WHERE cluster_name = 'myCluster'; ``` 步骤2:将元数据中存储的GR组名更新为当前实例的GR组名(即上面查询得到的current_gr_name): ```sql UPDATE mysql_innodb_cluster_metadata.clusters SET attributes = JSON_SET(attributes, '$.group_replication_group_name', (SELECT @@group_replication_group_name)) WHERE cluster_name = 'myCluster'; ``` 步骤3:再次尝试恢复集群: ```javascript \js var cluster = dba.rebootClusterFromCompleteOutage("myCluster", { force: true, timeout: 120 }); ``` 如果仍然失败,可能需要检查元数据中其他不一致的地方,或者采用更激进的恢复方法(如之前提到的重建元数据)。 但是,根据您提供的信息,当前实例在元数据中存在且地址正确,唯一不一致的是GR组名,因此更新GR组名后应该可以恢复。 注意:在执行上述更新之前,请确保当前实例的GR组名是正确的(即整个集群应该使用同一个GR组名)。如果有多个实例,其他实例的GR组名也应该相同。如果不同,那么需要将整个集群的GR组名统一(通常以主实例的GR组名为准)。 如果其他实例的GR组名不一致,需要分别连接上去检查并修改(注意:修改GR组名需要重启Group Replication,甚至可能重新引导集群)。 因此,完整的恢复步骤可能如下: 1. 选择一个实例作为基准(通常是原主节点),记录其`@@group_replication_group_name`。 2. 更新元数据中的GR组名为该值。 3. 对于其他实例,如果GR组名不一致,需要停止Group Replication,设置全局变量`group_replication_group_name`为正确的值(注意:该变量是只读的,只能在启动GR之前设置,所以需要先停止GR,然后设置,再启动GR。但是,在MySQL 8.0.21之后,可以在运行时修改,但需要整个组一致)。 4. 然后再次尝试恢复。 但是,由于目前集群处于完全宕机状态,我们只需要恢复一个实例(作为引导节点),所以先更新元数据,然后尝试在当前实例上恢复集群。 代码实现: 步骤1:在MySQL Shell中执行SQL查询和更新(注意:需要先切换到SQL模式) ```javascript \js // 获取当前实例的GR组名 var currentGrName = session.runSql("SELECT @@group_replication_group_name").fetchOne()[0]; // 切换到SQL模式执行更新 \sql UPDATE mysql_innodb_cluster_metadata.clusters SET attributes = JSON_SET( attributes, '$.group_replication_group_name', ?) WHERE cluster_name = 'myCluster'; -- 使用绑定参数,将currentGrName传入 ``` 但是,在MySQL Shell中,我们可以这样操作: ```javascript \js // 使用SQL模式执行更新 session.runSql("UPDATE mysql_innodb_cluster_metadata.clusters SET attributes = JSON_SET(attributes, '$.group_replication_group_name', ?) WHERE cluster_name = ?", [session.runSql("SELECT @@group_replication_group_name").fetchOne()[0], "myCluster"]); // 然后尝试恢复 try { var cluster = dba.rebootClusterFromCompleteOutage("myCluster", { force: true, timeout: 120 }); print("恢复成功!"); } catch (e) { print("恢复失败: " + e.message); } ``` 如果上述方法仍然不行,可能还需要检查元数据中是否有其他不一致的地方,例如集群的拓扑类型、实例的状态等。 另外,还可以尝试使用更底层的方法:先停止当前实例的Group Replication,然后以引导模式启动,再通过dba.rebootClusterFromCompleteOutage恢复。因为有时候GR组名不一致可能是由于引导过程出现问题。 完整代码: ```javascript \js // 停止Group Replication session.runSql("STOP GROUP_REPLICATION"); // 设置引导模式并启动 session.runSql("SET GLOBAL group_replication_bootstrap_group=ON"); session.runSql("START GROUP_REPLICATION"); session.runSql("SET GLOBAL group_replication_bootstrap_group=OFF"); // 更新元数据中的GR组名 session.runSql("UPDATE mysql_innodb_cluster_metadata.clusters SET attributes = JSON_SET(attributes, '$.group_replication_group_name', ?) WHERE cluster_name = ?", [session.runSql("SELECT @@group_replication_group_name").fetchOne()[0], "myCluster"]); // 再次尝试恢复 try { var cluster = dba.rebootClusterFromCompleteOutage("myCluster", { force: true, timeout: 120 }); print("恢复成功!"); } catch (e) { print("恢复失败: " + e.message); } ``` 注意:在停止Group Replication后,当前实例可能没有可用的数据,因此需要确保数据是最新的(在完全宕机的情况下,可能每个实例的数据都不一致,需要根据具体情况选择数据最新的节点进行恢复)。 如果以上方法都失败,那么可能需要考虑重建元数据(使用adoptFromGR)或者从备份中恢复元数据。 由于问题复杂,请根据实际情况选择方案。 最后,我们提供相关的问题供进一步学习: §§相关问题§§: 1. 如何安全地修改InnoDB Cluster的Group Replication组名? 2. 在InnoDB Cluster中,元数据表`mysql_innodb_cluster_metadata`的结构是怎样的? 3. 当InnoDB Cluster完全宕机时,如何选择数据最新的节点进行恢复? 4. 使用`dba.rebootClusterFromCompleteOutage`恢复集群时,`force`参数的作用是什么?</think>### 诊断分析与解决方案 根据您的查询结果,我发现了关键问题:**元数据中存储的GR组名与当前实例实际GR组名不一致**。以下是详细分析和解决方案: #### 问题诊断 ```plaintext +-------------+----------------------+--------------------------------------+----------------------+--------------------------------------+--------------------------------------+-----------------------+ | instance_id | address | mysql_server_uuid | instance_name | current_uuid | current_gr_name | current_local_address | +-------------+----------------------+--------------------------------------+----------------------+--------------------------------------+--------------------------------------+-----------------------+ | 1 | 192.168.199.137:3306 | e5d3a92b-5636-11f0-83d2-000c292cd265 | 192.168.199.137:3306 | e5d3a92b-5636-11f0-83d2-000c292cd265 | 9f8c6f7e-5652-11f0-a2e0-000c292cd265 | 192.168.199.137:3306 | +-------------+----------------------+--------------------------------------+----------------------+--------------------------------------+--------------------------------------+-----------------------+ ``` 关键不一致点: 1. **GR组名不匹配**: - 元数据中存储的GR组名(未显示,但集群元数据中记录) - 当前实例实际GR组名:`9f8c6f7e-5652-11f0-a2e0-000c292cd265` 2. **UUID验证**: - 实例UUID匹配:`e5d3a92b-5636-11f0-83d2-000c292cd265` - 地址信息匹配:`192.168.199.137:3306` #### 修复方案 ##### 1. 更新元数据中的GR组名 ```sql -- 查询当前集群元数据中的GR组名 SELECT JSON_EXTRACT(attributes, '$.group_replication_group_name') AS stored_gr_name FROM mysql_innodb_cluster_metadata.clusters WHERE cluster_name = 'myCluster'; -- 更新为当前实际的GR组名 UPDATE mysql_innodb_cluster_metadata.clusters SET attributes = JSON_SET( attributes, '$.group_replication_group_name', '9f8c6f7e-5652-11f0-a2e0-000c292cd265' ) WHERE cluster_name = 'myCluster'; ``` ##### 2. 强制恢复集群 (MySQL Shell) ```javascript // 停止并重置Group Replication session.runSql('STOP GROUP_REPLICATION'); session.runSql('RESET MASTER'); session.runSql('RESET SLAVE ALL'); // 设置正确的GR组名 session.runSql(`SET GLOBAL group_replication_group_name = '9f8c6f7e-5652-11f0-a2e0-000c292cd265'`); // 以引导模式启动 session.runSql('SET GLOBAL group_replication_bootstrap_group=ON'); session.runSql('START GROUP_REPLICATION'); session.runSql('SET GLOBAL group_replication_bootstrap_group=OFF'); // 强制恢复集群 var cluster = dba.rebootClusterFromCompleteOutage("myCluster", { force: true, grGroupName: '9f8c6f7e-5652-11f0-a2e0-000c292cd265', // 显式指定GR组名 timeout: 120 }); print("集群恢复成功:", cluster.status()); ``` ##### 3. 完整恢复脚本 ```javascript \js try { // 尝试标准恢复 var cluster = dba.rebootClusterFromCompleteOutage("myCluster", { force: true, timeout: 120 }); } catch (e) { // 修复元数据 \sql UPDATE mysql_innodb_cluster_metadata.clusters SET attributes = JSON_SET( attributes, '$.group_replication_group_name', @@group_replication_group_name ) WHERE cluster_name = 'myCluster'; // 重置GR状态 \js session.runSql('STOP GROUP_REPLICATION'); session.runSql('SET GLOBAL group_replication_bootstrap_group=ON'); session.runSql('START GROUP_REPLICATION'); session.runSql('SET GLOBAL group_replication_bootstrap_group=OFF'); // 再次尝试恢复 cluster = dba.rebootClusterFromCompleteOutage("myCluster", { force: true, grGroupName: session.runSql('SELECT @@group_replication_group_name').fetchOne()[0], timeout: 180 }); } // 验证状态 if (cluster) { print("集群状态:"); print(JSON.stringify(cluster.status({extended:1}), null, 2)); } else { throw new Error("集群恢复失败"); } ``` ### 关键问题解析 1. **GR组名不一致的原因**: - 集群配置变更后未同步更新元数据 - 手动修改GR组参数导致与元数据不一致 - 从备份恢复后元数据未更新 2. **预防措施**: ```sql -- 创建元数据同步触发器 DELIMITER $$ CREATE TRIGGER sync_gr_metadata AFTER UPDATE ON performance_schema.global_variables FOR EACH ROW BEGIN IF NEW.VARIABLE_NAME = 'group_replication_group_name' THEN UPDATE mysql_innodb_cluster_metadata.clusters SET attributes = JSON_SET( attributes, '$.group_replication_group_name', NEW.VARIABLE_VALUE ) WHERE cluster_name = 'myCluster'; END IF; END$$ DELIMITER ; ``` 3. **自动化监控脚本**: ```python #!/usr/bin/env python3 import mysql.connector from mysql.connector import errorcode def check_gr_consistency(): config = { 'user': 'monitor_user', 'password': 'secure_password', 'host': 'localhost', 'database': 'mysql_innodb_cluster_metadata' } try: cnx = mysql.connector.connect(**config) cursor = cnx.cursor(dictionary=True) # 获取当前GR组名 cursor.execute("SELECT @@group_replication_group_name AS gr_name") current_gr = cursor.fetchone()['gr_name'] # 获取元数据中的GR组名 cursor.execute(""" SELECT JSON_EXTRACT(attributes, '$.group_replication_group_name') AS stored_gr FROM clusters WHERE cluster_name = 'myCluster' """) stored_gr = cursor.fetchone()['stored_gr'].strip('"') # 比较并修复 if current_gr != stored_gr: print(f"不一致发现: 当前GR组名={current_gr}, 存储GR组名={stored_gr}") cursor.execute(f""" UPDATE clusters SET attributes = JSON_SET( attributes, '$.group_replication_group_name', '{current_gr}' ) WHERE cluster_name = 'myCluster' """) cnx.commit() print("元数据已更新") except mysql.connector.Error as err: print(f"数据库错误: {err}") finally: if cnx.is_connected(): cursor.close() cnx.close() if __name__ == "__main__": check_gr_consistency() ``` ### 恢复流程图 ```mermaid graph TD A[启动恢复] --> B{实例在元数据中?} B -->|是| C{GR组名匹配?} B -->|否| D[手动添加实例到元数据] C -->|是| E[标准恢复流程] C -->|否| F[更新元数据GR组名] F --> G[停止并重置GR] G --> H[设置正确GR组名] H --> I[引导模式启动GR] I --> J[强制恢复集群] J --> K{成功?} K -->|是| L[完成] K -->|否| M[重建元数据] M --> N[使用adoptFromGR] N --> L ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值