【问题标题】:Deleted database accidentally by a bash script, rescue pleasebash脚本意外删除了数据库,请救援
【发布时间】:2019-03-24 11:38:55
【问题描述】:

我的开发人员犯了一个巨大的错误,我们在服务器中找不到任何人的 mongo 数据库。求救!!!

他登录服务器,并在~/crontab/mongod_back.sh下保存了以下shell:

然后他运行./mongod_back.sh,然后有很多permission denied,然后他运行Ctrl+C。然后服务器自动关闭。

他尝试重新启动服务器,然后出现 grub 错误:

然后他联系了阿里云,工程师将磁盘连接到另一个工作服务器,以便他可以检查磁盘。然后,他意识到一些文件夹已经消失,包括/data/ mongodb 所在的位置!!!

1) 我们只是不明白 bash 如何破坏包括/data/ 在内的磁盘;

2) 当然,是否有可能找回/data/

PS:他之前没有拍过磁盘的快照。

【问题讨论】:

  • 对不起,这是关于文件系统,而不仅仅是数据库......
  • 跟shell有关。我们不明白 shell 怎么会删除这些文件夹。也许还有其他原因?
  • 了解 shell 如何删除这些文件夹将有助于我们恢复它们。
  • @SoftTimur:如果你想找回数据,那你就来错地方了。如果您想知道代码有什么问题以及如何做得更好,那么您就在这里。
  • 我认为这也不得不说:认为//bash 中引入评论的人没有业务涉及生产服务器。

标签: bash filesystems ubuntu-14.04 data-recovery disaster-recovery


【解决方案1】:

问题 1

  1. 我们只是不明白 bash 如何破坏包括 /data/ 在内的磁盘;

原因:$OUT_DIR 未设置

bashsh 中,cmets 写为# comment,而不是// comment
下面一行会有以下效果

someVariable=someValue // not a comment
  • someValue 分配给环境变量someVariable,但仅适用于该命令。在该命令之后变量将恢复为旧值,在本例中为 null。
  • 执行“命令”// not a comment,即带有参数notacomment的程序//。由于// 只是一个目录(与/ 相同),这将导致错误消息,仅此而已。

目前这种行为可能看起来很奇怪,但您可能已经在IFS= read -r lineLC_ALL=C sort 等知名习语中使用过它。

查看您的脚本,以下几行可能导致了问题:

OUT_DIR=/data/backup/mongodb/tmp // ...
...
rm -rf $OUT_DIR/*

很抱歉给你带来这个,但你基本上执行了rm -rf /*,因为$OUT_DIR扩展为空字符串。

其他系统的潜在风险

即使$OUT_DIR 不是空的,效果可能是相同的,因为在rm 之后有一个//“评论”。考虑命令

rm -rf some // thing

这应该删除三个文件/目录some//thing。正如已经指出的那样,/// 是同一目录。

然而,大多数在 Linux 上的rm 实现对这种情况都有保护,不会轻易删除/。在 Ubuntu 上,您将收到以下警告(不要在家里尝试。如果您的 rm 不同,会很糟糕。

$ rm -rf //
rm: it is dangerous to operate recursively on '//' (same as '/')
rm: use --no-preserve-root to override this failsafe

问题2

  1. 当然,是否可以取回 /data/?

这与 StackOverflow 无关。但是,你可以找到manyanswerstothisquestiononotherstackexchangesites

您可以尝试一些恢复工具,但如果您没有备份,则无法保证您可以恢复数据。

【讨论】:

  • 我还会在脚本中包含set -u -e——一旦发生错误或存在未分配的变量,这将立即退出......并且可能使用bash -n my_script.sh
  • 如果你在 bash 中使用管道和陷阱,set -Eeuo pipefail 会更安全
  • 我尝试执行someVariable=someValue echo "someVariable=$someVariable",但它只输出someVariable=。答案是变量赋值只针对那一行。如果这是正确的,为什么我得到一个空值?
  • @VCD 因为变量在设置之前已经展开。 Bash 在多个步骤中处理命令,扩展变量 ($var) 是第一步,稍后分配值 var=... -- 如果是相反的方式,你就不能写像 var="...$var..." 这样的东西。¶ var=test bash -c 'echo "$var"' 你会得到预期的输出(注意单引号)。
  • nitpick:rm 的参数中还有另一个//,所以即使$OUT_DIR 设置正确也会是一场灾难
【解决方案2】:

语言之间的切换可能很棘手! // 不是 shell 中的评论启动器,它是 #。所有带有这些“cmets”的命令都被错误地解析并被跳过:

$ VAR=whatever // comment
bash: //: Is a directory
[$?=126]
$ echo "($VAR)"
()

因此,OUT_DIR=... 被忽略,$OUT_DIR 为空。很容易猜到是什么

rm -rf $OUT_DIR/*

然后做了。基本上相当于

rm -rf /*

使用您的备份来恢复数据库。

【讨论】:

  • 希望备份脚本是由其他人编写的。
【解决方案3】:

我可以看到评论区的中文,从第10行开始,用户想创建一个临时文件夹但使用cd,所以如果/data/backup/mongodb/tmp首先不存在,那么$OUT_DIR为空或null,在那之后第 11 行变成了rm -rf /*

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    相关资源
    最近更新 更多