完了,良许直播中删库了……

Posted 良许Linux

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了完了,良许直播中删库了……相关的知识,希望对你有一定的参考价值。

大家好,我是良许。

今天跟大家聊个尴尬的事,大家可以本着看热闹不嫌事大的心态来听我唠唠。

经常来我直播间(视频号+抖音)的小伙伴都知道,我最近一直都在直播间手把手现场写 Shell 脚本。

就在前天晚上,我写 Shell 脚本的时候,不小心把当前目录下所有脚本(连同这个脚本本身)全部删除了,而且还全程直播了……

这是我做直播到现在最大的一次直播事故啊。。

这个脚本的需求是这样的:把当前目录(包含子目录)下所有后缀为 ".sh" 的文件后缀变更为 ".shell",之后删除每个文件的第二行

我先把正确的脚本贴出来给各位看官看看:

#!/bin/bash 
ALL_SH_FILE=$(find . -type f -name "*.sh") 
for file in $ALL_SH_FILE[*] 
do 
    # filename=$file%.sh*
    filename=$(echo $file | awk -F'.sh' 'print $1') 
    new_filename="$filename.shell" 
    mv "$file" "$new_filename" 
    sed -i '2d' "$new_filename" 
done

这个需求看起来蛮多的,但仔细拆解一下,其实要求就下面这几个:

  1. 找到当前目录下所有以 .sh 结尾的文件;

  2. 遍历这些文件,将后缀改为 .shell

  3. 删除每个文件的第二行。

我们在写代码的时候,一定不要着急动手,先拆解一下,这样写起来就容易很多。下面就逐一解决这些需求。

需求1:找到当前目录下所有以 .sh 结尾的文件

找文件,很容易就想到 find 命令。

find 命令结合的选项无非就是:-type-name-size-mtime ,其它的相对而言用得比较少。在这里,很明显使用 -type-name

要是连 find 命令都用不熟的小伙伴,赶紧拍一拍文末的命令课。

$ find . -type f -name "*.sh"

需求2:遍历这些文件,将后缀改为 .shell

遍历文件问题也不大,就是使用 for xxx in yyy 这种格式,这里的 yyy 就是我们上面找到的全部后缀 .sh 文件。

然后就是改后缀,肯定要使用到 mv 命令了。我们一般是这样修改文件名的:

$ mv old_filename new_filename

这里 old_filename 好办,就是我们一个个遍历的文件名。关键是 new_filename ,怎么拼凑出我们需求的文件名。

仔细分析一下,就是将 old_filename 里的 .sh 后缀去掉,再拼上 .shell 后缀。

去掉 .sh 后缀的方法有很多,这里介绍两个:

  1. 字符串切片
$ filename=$file%.sh*
  1. 利用 awk 命令切片

这里用到一个很巧妙的方法,就是把 .sh 视为分隔符,然后提取的第一列就是文件名了。

$ filename=$(echo $file | awk -F'.sh' 'print $1') 

这样我们就得到了没有 .sh 后缀的文件名了,我们再拼上 .shell 后缀就行了。

$ new_filename="$filename.shell" 

然后,我们再使用 mv 命令修改一下文件名就大功告成了。

需求3:删除每个文件的第二行

这个需求毫无难度,sed 一下就行了。所以说,文本处理三剑客在 Shell 脚本里真的是无处不在,大家一定要好好掌握。

$ sed -i '2d' "$new_filename" 

三个需求都实现之后,我们再写起代码来就没啥难度了。

直播中,为了演示方便,我创建了三个 .sh 后缀文件。

然后,我一顿操作猛如虎,很快就写好了代码。

当我雄心壮志敲下回车键运行脚本,打算在直播间秀一把时,得到了这样的结果:

完了,怎么结果跟我预想的不一样?

完了,我的那几个 .sh 文件呢??

完了,我的脚本本身去哪了???

完了,难道我删库了??

完了,两个直播间加起来有 400 多号人正盯着我看呢。。

完了完了,翻车了,出丑了,尴尬了。。

你们看我我上面的操作记录就可以看到此时的我内心有多慌乱。。

但我已经连续直播 5 个多月了,最高的时候有 3300+ 人在线,早已经身经百战,什么大风大浪没见过?

于是我迅速调整好心态,努力回想是什么原因导致了这次翻车事故。

但是脚本已经没了,只剩下孤零零的一个 new_filename 这个文件,想复查代码都没办法。

我努力回想,怎么也想不到到底哪里出错了。

这个new_filename 也一直在那边,仿佛瞪着眼睛看着我,也在嘲笑我。

今天在写这篇文章的时候,突然想到,所有的 .sh 文件都不见了,突然冒出了一个 new_filename 文件,或许可以从它下手。

再回看一眼代码,我恍然大悟!!

我特么在 mv 那里,new_filename 变量前忘记写了 $ 符号了!!然后就变成了这样:

$ mv "$file" "new_filename" 

这下好了,所有的 .sh 文件全部重命名成了 new_filename 了!

怪不得所有的 .sh 文件全部离奇失踪。。

我再写一遍代码,然后手动把 new_filename 前面的 $ 去掉,成功复现了昨晚的现象。

终于是真相大白了……

所以啊,写代码一定要慎重再慎重,小心再小心,否则的话就有可能出现这种意想不到的结果。

实际上,之前在公司上班的时候,我有一次误操作,把我自己的代码全部删除了。。还好有 Git ,否则我估计就要扫地出门了。。

Linux 下,不仅 rm 命令很危险,mvcp 命令同样也没你想得那么安分,一不小心就可能把文件移没了或者覆盖了。

所以大家在使用这三个命令的时候,一定要再三确认之后再敲回车键,否则可能连哭都来不及了。

大家一起引以为戒。

PS :直播中有个小插曲。有个黑粉看到我出错了,开始各种挖苦嘲讽。好在直播间大家都比较友好,纷纷帮我怼回去。

写代码哪可能不会出错?你要是那么厉害,也没空来我直播间看我写代码。程序员本来就是边写代码边调试的,能够一次成功的,估计没几个人能做到。

而且这种人,大概率在现实中也是唯唯诺诺,在领导面前卑躬屈膝,薪资不过万之人。只有在网络上去喷别人,才可以找到一点存在感。

呵呵。


学习编程,千万不要急于求成,一定要多读一些经典书籍,多看源码,多下苦功夫去死磕代码,这样技术才能长进。给大家分享一些程序员必读经典书籍,一定要多读几遍:

有收获?希望老铁们来个三连击,给更多的人看到这篇文章

推荐阅读:

欢迎关注我的博客:良许Linux教程网,满满都是干货!

MySQL删库了怎么整?

    专业演示,生产环境请勿模仿!哈哈哈哈哈~

一、恢复方案

1.1、数据量不是特别大,可以将mysqldump命令备份的数据使用mysql客户端命令或者source命令完成数据的恢复;

1.2、使用Xtrabackup完成数据库的物理备份恢复,期间需要重启数据库服务;

1.3、使用LVM快照卷完成数据库物理备份恢复,期间需要重启数据库服务;

二、使用mysqlbinlog进行时间点恢复

2.1、介绍

    mysqlbinlog是一个从二进制日志中读取语句的工具,在mysql安装完成之后自带的。

2.2、二进制日志恢复原理

    当使用mysqldump对数据库进行备份时,生成的备份文件中包含了数据库DML操作时的时间点以及备份时的二进制日志位置信息,如果单库,可以从某个时间点开始,进行时间点恢复;如果是主从架构,可以根据备份时的--master-data=2和--single-transaction,完成根据时间点或者位置点的恢复。

2.3、二进制日志恢复示例

2.3.1、单库恢复示例

    创建数据库,并插入测试数据

mysql> SHOW CREATE DATABASE test_db;
mysql> CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `age` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
# 插入测试数据
mysql> INSERT INTO student (name,age) VALUES('Jack',23),('Tomcat',24),('XiaoHong',22),('ZhangFei',29);

    使用mysqldump进行全量备份,备份时滚动日志,同时记住二进制日志文件名称和日志的位置点

[root@WB-BLOG ~]# mysqldump -uroot -proot \
-h127.0.0.1 -P3306 \
--databases test_db \
--single-transaction \
--triggers --routines \
--flush-logs \
--events > /tmp/test_db.sql

# 记住二进制日志文件名称和日志位置点
[root@WB-BLOG ~]# mysql -e "show binary logs" > bin_pos_`date +%F`.out

    此时查看二进制日志文件名称和日志点位置如下

mysql> SHOW BINARY LOGS;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |      1497 |
| mysql-bin.000002 |       397 |
+------------------+-----------+
2 rows in set (0.00 sec)

    使用了一段时间,不小心误操作,执行了如下的语句,将数据库中的数据全部修改了

mysql> UPDATE STUDENT SET name = 'admin';

    过了一段时间,可能是几分钟,也可能是几个小时,有人反映网站登录有问题了,查看发现好多数据被误修改,而这段时间内,还一直有写入操作,如又新增了如下的记录

mysql> INSERT INTO student(name,age) VALUES('Hbase',23),('BlackHole',30);

    此时需要恢复数据,首先为了防止数据继续写入,可以先锁表,暂停写入业务,通知用户系统维护,然后执行如下操作:

#登录数据库,锁表,此时表只能读,不能写
mysql> USE test_db;
mysql> LOCK TABLE student READ;

#然后重新(注意是重新打开)打开一个session窗口,否则会话退出之后,锁就会释放。然后压缩备份现有数据和二进制日志文件
[root@WB-BLOG mysql_logs]# tar zcvf mysql_data.tar.gz /mysql_data/*
[root@WB-BLOG mysql_logs]# tar zcvf mysql_bin.tar.gz /mysql_logs/*

#导入最近备份的一次全备数据
[root@WB-BLOG ~]# mysql -uroot -proot -h127.0.0.1 -P3306 < /tmp/test_db.sql 

#查看全备时的二进制日志文件和日志点
[root@WB-BLOG ~]# cat bin_pos_2018-06-24.out 
    Log_name        File_size
    mysql-bin.000001      1497
    mysql-bin.000002       397

#将861这个点之后的二进制日志文件转换为一个sql文件
[root@WB-BLOG bin]# ./mysqlbinlog /mysql_logs/mysql-bin.000002 --start-position=397 > /tmp/tmp.sql

#使用vim编辑器编辑这个sql文件,找到其中的未加条件的UPDATE语句,然后将其删掉,然后将删掉UPDATE语句之后的sql脚本内容导入到数据库中
[root@WB-BLOG bin]# vim /tmp/tmp.sql
    use `test_db`/*!*/;
    SET TIMESTAMP=1522088753/*!*/;
    update student set name = 'admin'  #删掉这一句
[root@WB-BLOG bin]# mysql -uroot -proot -h127.0.0.1 -P3306 < /tmp/tmp.sql

#登录数据库查询数据是否恢复,可以查看被误修改的数据是否还原,然后对表执行解锁,再次全备数据
mysql> UNLOCK TABLES;
2.3.2、主从架构数据恢复示例
  • 环境

主库:192.168.199.10(node01)

从库:192.168.199.11(node02)

    首先停止从库的SQL线程,然后在从库上全备数据,并输入"SHOW SLAVE STATUS"信息到备份文件中,"SHOW SLAVE STATUS"的输出信息中记录了当前应用到了主库的哪个位置点的信息

#登录从库,然后关闭SQL线程
mysql> STOP SLAVE SQL_THREAD;
Query OK, 0 rows affected (0.01 sec)

#然后记录从库中当前应用的主库的二进制日志文件信息
[root@node02 mysql_data]# mysql -e "SHOW SLAVE STATUS \G" > slave_`date +%F`.info
[root@node02 mysql_data]# mysqldump -uroot -proot -h127.0.0.1 \
-P3306 --databases test_db \
--routines --triggers \
--single-transaction > /tmp/mysql_test_db_`date +%F`.sql

    在从库上备份完成之后,重新启动从库的SQL线程

mysql> START SLAVE SQL_THREAD;
Query OK, 0 rows affected (0.01 sec)

    启动SQL线程之后,备份这段时间内在主库上的DML操作会重新同步到从库上。假如在主库上发生了一个误操作,没加条件更新了student表中的所有数据,导致了表中所有数据被修改,此时由于同步操作,从库也被修改了

#登录主库,修改数据库的对外用户,使其暂不提供服务,然后滚动日志
mysql> UPDATE mysql.user SET Host = '127.0.0.1' WHERE User='tomcat';
Query OK, 1 rows affected (0.00 sec)

#刷新权限表
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

#滚动日志
mysql> FLUSH LOGS;
Query OK, 0 rows affected (0.01 sec)

#将从库备份的数据及备份时刻的从库slave信息传到主库上
[root@node02 mysql_data]# scp /tmp/mysql_test_db_2018-06-24.sql 192.168.199.10:/root/
[root@node02 mysql_data]# scp slave_2018-06-24.info node01:/root/

    备份主库的数据目录和二进制日志文件目录

[root@node01 mysql_logs]# tar zcvf mysql_master_data.tar.gz /mysql_data/*
[root@node01 mysql_logs]# tar zcvf mysql_logs.tar.gz /mysql_logs/*    

    导入从库最近一次备份的数据

[root@node01 mysql_logs]# mysql -uroot -proot -h127.0.0.1 -P3306 < /root/mysql_test_db_2018-03-26.sql 
#注意:上述的操作不能锁主库的表,否则全备数据无法导入。

    查看备份时刻的从库中应用到的主库二进制日志文件名称及位置点

[root@node01 mysql_logs]# cat /root/slave_2018-03-26.info
    Master_Log_File: master-bin.000002  #备份时所应用的主库二进制日志文件名称
    Read_Master_Log_Pos: 395   #备份时所应用的主库二进制日志文件的位置

    从该日志文件及日志点开始,将395日志点之后的日志文件转换为sql脚本,如果有多个二进制日志文件可以同时转换为sql脚本,如下所示

[root@node01 mysql_logs]# mysqlbinlog /mysql_logs/master-bin.000002 \
--start-position=395 > /tmp/tmp.sql

#将master-bin.000003,master-bin.000004,master-bin.000005合并到/tmp.sql文件中
[root@node01 mysql_logs]# mysqlbinlog /mysql_logs/master-bin.00000{3,4,5} --start-position=395 > /tmp/tmp.sql

    找到误操作的update语句,然后删除该语句,并将增量的sql脚本导入数据库

[root@node01 mysql_logs]# vim /tmp/tmp.sql
    use `test_db`/*!*/;
    update student set name = 'admin'  #删掉这一句
[root@node01 mysql_logs]# mysql -uroot -proot -h127.0.0.1 -P3306 < /tmp/tmp.sql 

    登录数据库,查看数据是否正常,被误修改的数据是否已经恢复,如果恢复,则在主库上全备数据,然后传到从库,完成从库恢复

[root@node01 mysql_data]# mysqldump -uroot -proot -h127.0.0.1 \
-P3306 --databases test_db --routines \
--triggers --single-transaction \
--master-date=1 > /tmp/master_test_db_`date +%F`.sql

[root@node01 mysql_data]# scp /tmp/master_test_db_2018-06-24.sql node01:/root/

#如果从库设置了只读,需要先去掉只读限制
mysql> SET GLOBAL read_only = OFF;
Query OK, 0 rows affected (0.00 sec)

#将数据导入从库
[root@node02 mysql_logs]# mysql -uroot -proot \
-h127.0.0.1 -P3306 < /root/master_test_db_2018-06-24.sql

#开启从库的只读
mysql> SET GLOBAL read_only = ON;
Query OK, 0 rows affected (0.00 sec)

    由于在主库上备份时添加了--master-date=1参数,所以从库导入之后,不需要重新执行change master操作。

    登录从库,查看SHOW SLAVE STATUS信息是否正常,如果正常,登录主库,重新修改授权表,然后对外提供服务

mysql> UPDATE mysql.user set Host = '192.168.0.%' WHERE User = 'tomcat';
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

    执行完成之后,主从数据恢复完毕。

    只有一台数据库服务器,执行"rm -rf /*"删库了,还没有任何的数据备份?该怎么办呢?

    这个时候啥都别想,赶紧跑,能跑多快跑多快,能跑多远跑多远!!!!!

近期精彩回顾:

   


    

常驻内容:

源码搭建:

关注菜鸟封神记,定期分享技术干货!

点赞在看是最大的支持,感谢↓↓↓

以上是关于完了,良许直播中删库了……的主要内容,如果未能解决你的问题,请参考以下文章

删库了,我不跑路,就是玩儿

Linux终端居然也可以做文件浏览器?

内部群炸锅了,同事又删库了

内部群炸锅了,同事又删库了。。

写了Bug,误执行 rm -fr /*,我删删删删库了,要跑路吗?

Ant Design 遭删库!