今天同学遇到了一个很多Linux使用者常见的问题:恢复grub。他的情况是这样的:硬盘上有两个操作系统,一个Windows 7,一个Ubuntu,由于Windows中毒(既然Windows容易坏为什么还要用。。),所以把Windows重装一遍,重装一遍后会发现在启动选项中没有Ubuntu了,这很正常,因为Windows的引导程序不能识别Ubuntu系统(这就是为什么Ubuntu要在Windows装后再装的原因),而重装系统会清掉原来的引导程序。为了能重新启动硬盘上的Ubuntu需要将Ubuntu的引导程序也就是grub装上。
首先从Ubuntu安装盘启动,选择试用模式,启动好之后打开终端,输入以下命令:
sudo fdisk -l
我分了多个Linux分区,分别为/dev/sda{6..11},其中sda9是我的根目录,sda6是我的/boot目录
由于是从CD启动的,硬盘上的分区都还没有挂载,所以先要将需要修改的一些分区挂载上来,执行以下命令:
sudo mount /dev/sda9 /mnt sudo mount /dev/sda6 /mnt/boot
其中第二个命令需要根据自己的情况运行,由于我将boot单独分一个区,所以我需要挂载boot分区来修改它,如果你没给boot单独分区,那么就不用执行第二条命令。
之后需要将一些虚拟的文件系统挂载到/mnt目录下,这样是为了模拟出从硬盘启动的所有文件系统的环境:
sudo mount --bind /proc /mnt/proc sudo mount --bind /dev /mnt/dev sudo mount --bind /sys /mnt/sys
之后便是一条非常重要的命令,如果你在进行grub-install时出现了/usr/sbin/grub-probe: error: cannot stat ‘aufs’提示,那么很有可能就是因为你没有执行下面这条命令:
sudo chroot /mnt
执行了这条命令之后你的终端已经几乎完全模拟出从硬盘启动的终端了,之后你执行的命令都对应的修改硬盘而不是修改不会保存的CD虚拟的文件系统了(对于一些特殊情况就不满足这条件了,比如需要修改/etc但是你将etc单独分区并且没有挂载到/mnt)。
之后执行以下命令:
update-grub grub-install /dev/sdX #sdX中的X对于你硬盘的号,一般是sda,注意不是sda7这样的分区号,而是直接指定整个硬盘,如果不是主硬盘就是sdb,以此类推
之后直接重启就行了。
联想
最近总是在思考过程式编程和纯函数式编程有什么区别,我觉得这是一个很好的例子。在这个还原grub的过程中我们做了很多的mount,并且还用到了几乎不会用到的chroot,这么多多余的步骤就是为了创造出一个正确的文件系统环境,好让我们在这个模拟的环境中执行没有参数的update-grub。从编程的角度来讲update-grub是个函数,但是这个函数写得非常不好,它竟然不靠参数来运行而是依赖于全局变量,这个全局变量就是我们刚刚费了很大劲才创造出来的文件系统环境,如果update-grub靠参数来运行(也就是说update-grub类似于纯函数式编程只靠参数运行而不依赖于全局变量),我们就只需要挂载boot分区再指定boot分区的位置就行,而不用为了这个依赖全局变量的函数而模拟出整个环境。我觉得这也算是函数式编程的一个好处之一了吧。