倍可親

回復: 2
列印 上一主題 下一主題

免得抓瞎:為你的硬碟作備份壓縮鏡像

[複製鏈接]

9

主題

75

帖子

290

積分

貝殼網友二級

Rank: 3Rank: 3

積分
290
跳轉到指定樓層
樓主
老石 發表於 2010-12-19 07:05 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
本帖最後由 老石 於 2010-12-19 07:15 編輯

為你的硬碟作一個壓縮鏡像的備份,以免在硬碟損壞,系統損壞,系統中毒,裝錯軟體時抓瞎。

我在《dd: 窮人的硬碟備份與恢復工具》中分享了如何做硬碟的鏡像備份和硬碟恢復的小經驗。不過,光用dd指令做硬碟備份,那麼備份鏡像文件佔據的空間和源盤空間一模一樣。較新的機器,不少內裝的硬碟高達500GB或1TB。那麼備份USB盤就需要有相應的空間。其實,硬碟上有許多未用空間,把未用空間也原樣備份實在是資源浪費。我們不妨把鏡像備份壓縮起來。

在《dd: 窮人的硬碟備份與恢復工具》一文中我們知道如何用dd作鏡像備份。我們用的指令類似於:
dd if=/dev/sda of=/media/sdc1/yourBackupDir/BACKUP.img bs=512k &

而現在,要製作壓縮鏡像備份,我們得把dd和gzip指令結合起來。以下是製作壓縮鏡像備份的指令:
dd if=/dev/sda ibs=512k | gzip > /media/sdc1/yourBackupDir/backup.gz

我解釋一下指令。
if (input file)跟隨的是輸入文件。這裡輸入文件是device下面的整個硬碟sda
這裡我們不見了of(輸出文件),而代之以另一個程序,叫gzip的壓縮程序。dd 程序的輸出被送往gzip,成了gzip的輸入。通過gzip的壓縮,它的輸出被記錄在文件backup.gz中。文件backup.gz的路徑是掛載於/media下的USB硬碟sdc1的文件夾yourBackupDir。

用這個指令,可以大大減少備份的空間。我的Lenovo S10-2 Netbook,配備160GB硬碟,安裝WINDOWS XP、Lenovo隨機軟體,TradeStation 8,OpenOffice,以及第二個操作系統「紅旗Linux 6.3」。它的壓縮鏡像備份是22.3GB。

那麼,壓縮的鏡像備份如何恢復呢?硬碟恢復的指令是:
gzip -dc /media/sdc1/yourBackupDir/backup.gz | dd of=/dev/sda obs=512k &

這條指令的意思是:
gzip的輸入是存於硬碟sdc1中的壓縮鏡像備份backup.gz。gzip 的 -d 表示解壓縮;-c 是把輸出寫到標準輸出端(通常是屏幕)。然後把gzip的輸出作為 dd 指令的輸入。而dd指令的輸出則是硬碟sda。 dd 指令的 obs=512k 表示 dd 的輸出緩衝是512k。就是說 dd 等待gzip的輸入,積累到了512k之後才向硬碟sda寫一次。

用dd和gzip結合的方法壓縮的效果不錯。不過對於使用多年的機器,壓縮效果就不如新的時候那麼好了。這是為什麼呢?

我們知道,文件壓縮的原理是建立一個索引表,用較短的字元串來替代較長的字元串。比如字元串:
「This_is_a_test._This_is_a_test._This_is_a_test._This_is_a_test._」(我在這裡用_表示空格,以便看清楚)。如果我們從左到右逐字掃描第一個重複是is_。在索引表裡我們建立第一個替代:
1        3        3        (第一目索引從第三個位置起,長度為3, 即is_所在的位置)

這樣,我們的字元串就可以寫成:
「This_1a_test._This_1a_test._This_1a_test._This_1a_test._」

我們接著掃描:「This_1a_test._」 又有重複。於是索引表就成了:
1        3        3
2        1        14        (第二目檢索從第一位起,長度為14)
於是,字元串可以些成:
「This_1a_test._222」
然後把檢索表加在壓縮文件後面,就形成了壓縮文件。所有文件的儲存最終都是2進位制的0和1的數字,重複率很高,所以壓縮很有效。

復原時,反向運作即可復原。

當然,這只是簡單說一下無損壓縮的原理。每個壓縮軟體都有可能有不同的做法。我們用的gzip具體怎麼工作的,我也不清楚。有興趣可以查看gzip的源碼。了解原理的目的是為了說明我的應用。

在前面解釋文件壓縮原理的那個例子中,我們看到,一個文件重複的字串越多,重複的字串越長,那麼壓縮效果越好。未寫過的空間原本都是2進位的0,會有很長、很多的重複,有利於壓縮。然而,在我們使用計算機的過程中,我們不斷新建文件,不斷刪除文件,不斷把文件來回複製、刪除或下載、刪除。操作系統本身也不斷生成各種文件,用完后又刪除。這些看似被刪除的文件其實並沒有真的被刪除。操作系統只是在文件管理系統的檢索表中把文件名的頭一個字母抹掉。這樣做,一是為了刪除的操作快,二是為了萬一用戶後悔,數據可以盡可以多地恢復。操作系統在創建新的文件時,會儘可能寫在完全未被使用過的空間,而不是寫在已經抹掉的文件空間。這也是為了萬一需要被刪除的文件盡可以多地恢復。但這個做法對壓縮卻不利的因素。因為原來未寫過的空間一色清的2進位0,現在可能被各種文件寫過後,重複率降低,從而降低了壓縮的效率。

我們有沒有辦法提高壓縮效率呢?有。答案還是能在dd指令中找到。那就是,先用dd指令把硬碟所有未用空間寫成0,這樣已被刪文件的空間就重新被0佔據。這個指令是:
dd if=/dev/zero of=/media/sda1/zerofile bs=512k &

它會在物理硬碟sda中第一個分區sda1下面建立一個以zerofile命名的文件(你可以給任何文件名)。在這個例子中,第一個分區sda1假設(通常也確實)是對應WINDOWS的C:\。dd會把0寫入這個文件,直到這個文件佔據硬碟分區sda1中所有的剩餘空間,無法再寫為止。之後,你再刪除這個zerofile,就能把所有未用空間重新歸0了。歸0之後再作硬碟的鏡像壓縮備份,那麼備份就會小很多。

這個過程涉及手動操作指令,容易出錯,而且你還得等待歸0操作完成後才能作壓縮備份的操作。比較麻煩。為了防止出錯,我編了一個腳本小程序 backup.sh。它可以在LINUX系統下運行。我喜歡的系統工具是KNOPPIX LINUX。這個腳本程序兩年來從無差錯。我放在這裡,供大家參考(見附錄)。

一次性準備:
1)在備份硬碟上,給要備份的計算機建一個文件夾。這個工作可以在視窗下做,也可以在Linux下面做。比如,在視窗下,我的備份硬碟是F:\,我要為Lenovo S10-2計算機做備份,我就創建F:\S10-2 (見下圖。我給每一台要備份的計算機創建了對應的文件夾)


2)把backup.sh腳本儲存到F:\S10-2。你可以COPY - PASTE到你的備份文件夾。(我在每個備份文件夾內,都有一個和該計算機一致的backup.sh腳本文件)

3)啟動Knoppix Linux前,除去所有外接USB儲存設備,只留備份USB硬碟。(這樣做的目的在於今後 Knoppix 在指定備份USB硬碟標識時總是一致。假如,唯一的USB硬碟就是備份硬碟,這次得到的標識是sdc,下次啟動時,你沒有多加外接USB硬碟,那麼這個備份硬碟得到的標識還是sdc。如果啟動時,你外接USB硬碟有時候多一個,有時少一個,那你就無法保證Knoppix每次都會把sdc的標識分配給備份USB硬碟。)

4)用Knoppix光碟啟動Knoppix Linux。選擇Graphical Programs -> Start1xde Full X Screen

5) 點擊桌面左下方的 「PCMan File Manager」


File Manger 打開如下圖所示。


6) 點擊左邊的硬碟標識,尋找源盤的標誌。
視窗系統下的C:\盤(即源盤)所在分區,在大多數情況下它標誌是sda1。你在File Manager左邊點擊各硬碟標識,如果見到WINDOWS系統下常見的文件夾時,就可以確定源盤在KNOPPIX系統下如何識別的。從上圖可以確定C:\盤是sda1,從而確定機器內裝的物理硬碟是的標識是sda。你的目的是把真箇物理硬碟備份起來。

7) 點擊「BACKUP」硬碟。目的是尋找「的盤」以及備份文件的路徑。
比如,我要為計算機S10-2作備份,我就一路點擊到「/media/sdc1/S10-2」。記住或複製這個備份路徑。(見下圖)


8) 修改backup.sh腳本文件,使其符合你的計算機系統的特定設置。
點擊左下角的企鵝標識Start -> Accessories -> LeafPad。
到你所要做備份的文件夾下,打開backup.sh(即在第二步中保存的腳本文件)。在我的例子中,我打開的是
/media/sdc1/S10-2/backup.sh

確認或者修改第一、二行,使其符合你的系統。下面兩行的紅色部分是你要在腳本文件 backup.sh 內改動的地方。

SOURCE_DISK=sda                                # 源盤命名,須與第6步得到的結果一致。
TARGET_DIR=/media/sdb1/S10-2/`date +"%Y_%m%d"`
                                                                # 的盤及備份文件夾,須與第7步的結果一致。


然後儲存這個腳本文件。

好了,現在腳本文件backup.sh完全符合了你特定的那個計算機系統。以後每次用KNOPPIX LINUX啟動時,只要備份硬碟是唯一的外接硬碟,你就可以放心使用這個腳本文件backup.sh。

製作備份的具體操作方法:
現在我們來使用backup.sh這個腳本。
1) 點擊桌面左下方 Terminal emulator


2) 在Terminal emulator里,轉到的盤備份文件夾下。在我的例子中,我輸入指令如下:
cd /media/sdc1/S10-2

3) 在「的盤」的備份文件夾下,運行剛才改動過的backup.sh指令。在我的例子中,我在/media/sdc1/S10-2下發出以下指令:
./backup.sh > backup.log &

你可以尾隨backup.log來觀察進度。指令是:
tail -f backup.log

4) 完成備份。
backup.sh程序會在備份文件夾下創建一個以當天日期命名的文件夾,並在該文件夾下生成一個壓縮的鏡像備份img.gz,以及一個硬碟恢復指令文件restore.sh。

在我的例子中,假設我在2010年11月13日作備份,那麼backup.sh會創建
/media/sdc1/S10-2/2010_1113
並且在此之下生成img.gz 和 restore.sh。


硬碟恢復的具體操作方法:
1) 在計算機啟動前,除去所有外接USB硬碟,只留備份USB硬碟。
2) 用Knoppix光碟啟動Knoppix Linux。選擇Graphical Programs -> Start1xde Full X Screen。
3) 打開File Manager,點擊源盤和的盤(確保它們掛載)。
4) 打開Terminal emulator,到你的備份文件夾。在我的例子中,我要到
/media/sdc1/S10-2/2010_1113
5) 在此,輸入指令:
./restore.sh &

注意事項:
硬碟備份時,需要較長時間。因為它幾乎為硬碟寫了兩遍。第一遍是歸0。第二遍是備份。而硬碟復原會很快。160GB的硬碟不到兩小時就完成了。

我的腳本程序可以跳過歸0這一步。這樣備份時會快一些,但是備份后的文件會大一些。跳過歸0步驟的指令是:
./backup.sh noClean &

如果你想測試我的腳本程序的準確性,你可以多接一個2GB的USB閃盤。用第6步和第7步確定閃盤和備份硬碟的標識。然後把閃盤的物理標識作為SOURCE_DISK,把備份硬碟的備份文件夾作為TARGET_DIR。因為閃盤小,備份會在幾分鐘內做完。之後換一個2GB的閃盤接上做閃盤恢復。然後你可以比較兩個閃盤是否有同樣的內容。(注意,每次外接硬碟數量改變時,你要重新確證SOURCE_DISK和TARGET_DIR的準確性,不可馬虎。

附錄:
#/bin/sh

###############################################################
# script:       backup.sh
# Author:       Shi WJ
# Date:         2008.12.
# Purpose:      Backup disk to an compressed image file.
###############################################################
SOURCE_DISK=sda
TARGET_DIR=/media/sdb1/S10-2/`date +"%Y_%m%d"`

# Note: you need to make sure that the source disk is correct, and the
#       target directory is changed to correctly reflect your system.



if [ $# -gt 1 ]
then
        echo "Usage:"
        echo "  backup.sh [noClean]"
        echo "  Without [noClean], cleaning is automatic."
        exit -1
fi
CLEAN=Y
if [ $# -eq 1 ]
then
        if [ $1 != "noClean" ]
        then
                echo "Usage:"
                echo "  backup.sh [noClean]"
                echo "  Without [noClean], cleaning is automatic."
                exit -1
        fi
        CLEAN=N
        echo `date +"%Y/%m/%d %H:%M:%S"` "      Starting Disk backup in 'noCleaning' Mode."
else
        echo `date +"%Y/%m/%d %H:%M:%S"` "      Starting Disk backup in 'Cleaning' Mode."
        echo "                  FYI, './backup.sh noClean' could be used for Non-cleaning mode backup."
fi

echo `date +"%Y/%m/%d %H:%M:%S"` "      Source Disk to be backed up: $SOURCE_DISK"
echo `date +"%Y/%m/%d %H:%M:%S"` "      The backup image will be located in: $TARGET_DIR"

echo `date +"%Y/%m/%d %H:%M:%S"` "      Checking the backup source directory..."
SOURCE_MOUNTED=N
for SOURCE_DIR in /media/${SOURCE_DISK}*
do
        if [ -d ${SOURCE_DIR} ]
        then
                echo `date +"%Y/%m/%d %H:%M:%S"` "      Source Mounted: ${SOURCE_DIR}"
                SOURCE_MOUNTED=Y
        fi
done

if [ ${SOURCE_MOUNTED} = "N" ]
then
        echo `date +"%Y/%m/%d %H:%M:%S"` "      No source directory is not mounted. Exiting..."
        exit -1
fi

echo `date +"%Y/%m/%d %H:%M:%S"` "      Checking the backup target directory..."
if [ ! -d ${TARGET_DIR} ]
then
        echo `date +"%Y/%m/%d %H:%M:%S"` "      Backup target directory ${TARGET_DIR} does not exist. Creating..."
        mkdir ${TARGET_DIR}
        if [ $? -eq 0 ]
        then
                echo `date +"%Y/%m/%d %H:%M:%S"` "      Backup target directory ${TARGET_DIR} created."
        else
                echo `date +"%Y/%m/%d %H:%M:%S"` "      Failed to create backup target directory ${TARGET_DIR}. Exiting..."
                exit -1
        fi
else
        echo `date +"%Y/%m/%d %H:%M:%S"` "      Backup target directory ${TARGET_DIR} exists."
fi

if [ $CLEAN = "Y" ]
then
        echo `date +"%Y/%m/%d %H:%M:%S"` "      Ready to clean the free space in source disk before backup."
        for SOURCE_DIR in /media/${SOURCE_DISK}*
        do
                if [ -d ${SOURCE_DIR} ]
                then
                        echo `date +"%Y/%m/%d %H:%M:%S"` "      Cleaning unused space of ${SOURCE_DIR}..."
                        dd if=/dev/zero of=${SOURCE_DIR}/zerofile bs=512k
                        rm ${SOURCE_DIR}/zerofile
                fi
        done
else
        echo `date +"%Y/%m/%d %H:%M:%S"` "      Source disk cleaning skipped."
fi

echo `date +"%Y/%m/%d %H:%M:%S"` "      Backup the entire hard disk to the image file..."
dd if=/dev/sda ibs=512k | gzip > ${TARGET_DIR}/img.gz
echo `date +"%Y/%m/%d %H:%M:%S"` "      Backup complete. The image file: ${TARGET_DIR}/img.gz"

echo "gzip -dc $TARGET_DIR/img.gz | dd of=/dev/sda obs=512k &" > $TARGET_DIR/restore.sh
echo `date +"%Y/%m/%d %H:%M:%S"` "      restore.sh created ${TARGET_DIR}/restore.sh"
echo "Good-bye"
exit 0

0

主題

19

帖子

4

積分

註冊會員

Rank: 1

積分
4
沙發
conke 發表於 2010-12-31 10:36 | 只看該作者
高手的好帖.


回復 支持 反對

使用道具 舉報

9

主題

75

帖子

290

積分

貝殼網友二級

Rank: 3Rank: 3

積分
290
3
 樓主| 老石 發表於 2011-1-1 01:54 | 只看該作者
回復 conke 2樓 的帖子

多謝了!
回復 支持 反對

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 註冊

本版積分規則

關於本站 | 隱私權政策 | 免責條款 | 版權聲明 | 聯絡我們

Copyright © 2001-2013 海外華人中文門戶:倍可親 (http://big5.backchina.com) All Rights Reserved.

程序系統基於 Discuz! X3.1 商業版 優化 Discuz! © 2001-2013 Comsenz Inc.

本站時間採用京港台時間 GMT+8, 2024-4-24 16:58

快速回復 返回頂部 返回列表