第 10 章 資料管理

目录

10.1. 共享,拷貝和存檔
10.1.1. 存檔和壓縮工具
10.1.2. 複製和同步工具
10.1.3. 歸檔語法
10.1.4. 複製語法
10.1.5. 查詢檔案的語法
10.1.6. 歸檔媒體
10.1.7. 可移動儲存裝置
10.1.8. 選擇用於分享資料的檔案系統
10.1.9. 網路上的資料分享
10.2. 備份和恢復
10.2.1. 實用備份套件
10.2.2. 一個系統備份的指令碼例子
10.2.3. 用於備份資料的複製指令碼
10.3. 資料安全基礎
10.3.1. GnuPG 金鑰管理
10.3.2. 在檔案上使用 GnuPG
10.3.3. 在 Mutt 中使用 GnuPG
10.3.4. 在 vim 中使用 GnuPG
10.3.5. MD5 校驗和
10.4. 原始碼合併工具
10.4.1. 從原始碼檔案匯出差異
10.4.2. Merging updates for source files
10.4.3. Updating via 3-way-merge
10.5. Version control systems
10.5.1. Comparison of VCS commands
10.6. Git
10.6.1. 配置 Git 客戶端
10.6.2. Git 參考
10.6.3. Git 命令
10.6.4. 用於 Subversion 倉庫的 Git
10.6.5. 記錄配置歷史的 Git
10.7. CVS
10.7.1. Configuration of CVS repository
10.7.2. Local access to CVS
10.7.3. Remote access to CVS with pserver
10.7.4. Remote access to CVS with ssh
10.7.5. Importing a new source to CVS
10.7.6. File permissions in CVS repository
10.7.7. Work flow of CVS
10.7.8. Latest files from CVS
10.7.9. Administration of CVS
10.7.10. Execution bit for CVS checkout
10.8. Subversion
10.8.1. Subversion 儲存庫的配置
10.8.2. 通過 Apache2 伺服器訪問 Subversion
10.8.3. 按組本地訪問 Subversion
10.8.4. 通過 SSH 遠端訪問 Subversion
10.8.5. Subversion 目錄結構
10.8.6. 往 Subversion 裡匯入一個新的源
10.8.7. Subversion 工作流

以下是關於在 Debian 系統上管理二進位制和文字資料的工具及其相關提示。

[警告] 警告

The uncoordinated write access to actively accessed devices and files from multiple processes must not be done to avoid the race condition. File locking mechanisms using flock(1) may be used to avoid it.

資料的安全和它的受控共享有如下幾個方面。

  • 存檔檔案的建立

  • 遠端儲存訪問

  • 複製

  • 跟蹤修改歷史

  • 促進資料共享

  • 防止未經授權的檔案訪問

  • 檢測未經授權的檔案修改

這些可以通過使用工具集來實現。

  • 存檔和壓縮工具

  • 複製和同步工具

  • 網路檔案系統

  • 移動儲存媒介

  • 安全 shell

  • 認證體系

  • 版本控制系統工具

  • Hash and cryptographic encryption tools

以下是 Debian 系統上可用的存檔和壓縮工具的預覽。

表 10.1. 存檔和壓縮工具列表

軟件包 流行度 大小 副檔名 命令 描述
tar V:908, I:999 2770 .tar tar(1) 標準的歸檔工具(預設)
cpio V:305, I:998 720 .cpio cpio(1) Unix System V 風格的歸檔器,與 find(1) 一起使用
binutils V:177, I:715 23348 .ar ar(1) 建立靜態庫的歸檔工具
fastjar V:5, I:56 172 .jar fastjar(1) Java 歸檔工具(類似 zip)
pax V:17, I:54 170 .pax pax(1) 新的 POSIX 歸檔工具,介於 tarcpio 之間
gzip V:877, I:999 231 .gz gzip(1), zcat(1), … GNU LZ77 壓縮工具(預設)
bzip2 V:238, I:933 184 .bz2 bzip2(1), bzcat(1), … Burrows-Wheeler block-sorting 壓縮工具有著比 gzip(1) 更高的壓縮率 (跟 gzip 有著相似的語法但速度比它慢)
lzma V:4, I:60 126 .lzma lzma(1) LZMA 壓縮工具有著比 gzip(1) 更高的壓縮率(不推薦)
xz-utils V:322, I:952 516 .xz xz(1), xzdec(1), … XZ 壓縮工具有著比 bzip2(1) 更高的壓縮率(壓縮速度慢於 gzip 但是比 bzip2 快; LZMA 壓縮工具的替代品)
p7zip V:38, I:175 934 .7z 7zr(1), p7zip(1) 有著更高壓縮率的 7-zip 檔案歸檔器(LZMA 壓縮)
p7zip-full V:175, I:527 4407 .7z 7z(1), 7za(1) 有著更高壓縮率的 7-Zip 檔案歸檔器(LZMA 壓縮和其他)
lzop V:5, I:44 97 .lzo lzop(1) LZO 壓縮工具有著比 gzip(1) 更高的壓縮和解壓縮速度 (跟 gzip 有著相似的語法但壓縮率比它低)
zip V:47, I:395 608 .zip zip(1) InfoZip:DOS 歸檔器和壓縮工具
unzip V:271, I:791 534 .zip unzip(1) InfoZIP:DOS 解檔器和解壓縮工具

[警告] 警告

除非你知道將會發生什麼,否則不要設定 "$TAPE" 變數。它會改變 tar(1) 的行為。

[注意] 注意

gzipped tar(1) 歸檔器用於副檔名是 ".tgz" 或者 ".tar.gz" 的檔案。

[注意] 注意

xz-compressed tar(1) 歸檔器用於副檔名是 ".txz" 或者 ".tar.xz" 的檔案。

[注意] 注意

FOSS 工具,例如 tar(1),中的主流壓縮方法已經按如下所示的遷移: gzipbzip2xz

[注意] 注意

cp(1),scp(1)tar(1) 工具可能並不適用於一些特殊的檔案。cpio(1) 工具的適用範圍是最廣的。

[注意] 注意

cpio(1) is designed to be used with find(1) and other commands and suitable for creating backup scripts since the file selection part of the script can be tested independently.

[注意] 注意

Libreoffice 資料檔案的內部結構是 ".jar" 檔案。

以下是 Debian 系統上的可用的簡單複製和備份工具的預覽。


在複製檔案的時候, rsync(8) 比其他工具提供了更多的特性。

  • 差分傳輸演算法只會傳送原始檔與已存在的目標檔案之間的差異部分

  • 快速檢查演算法 (預設) 會查詢大小或者最後的修改時間有變化的檔案

  • "--exclude" 和 "--exclude-from" 選項類似於 tar(1)

  • "a trailing slash on the source directory" syntax that avoids creating an additional directory level at the destination.

[提示] 提示

Execution of the bkup script mentioned in 第 10.2.3 节 “用於備份資料的複製指令碼” with the "-gl" option under cron(8) should provide very similar functionality as Plan9's dumpfs for the static data archive.

[提示] 提示

Version control system (VCS) tools in 表 10.11 “List of version control system tools” can function as the multi-way copy and synchronization tools.

如下是用不同的工具複製整個 "./source" 目錄中的內容。

  • 本地複製: "./source" 目錄 → "/dest" 目錄

  • 遠端複製:本地主機上的 "./source" 目錄 → "user@host.dom" 主機上的 "/dest" 目錄

rsync(8):

# cd ./source; rsync -aHAXSv . /dest
# cd ./source; rsync -aHAXSv . user@host.dom:/dest

You can alternatively use "a trailing slash on the source directory" syntax.

# rsync -aHAXSv ./source/ /dest
# rsync -aHAXSv ./source/ user@host.dom:/dest

或者,如下所示。

# cd ./source; find . -print0 | rsync -aHAXSv0 --files-from=- . /dest
# cd ./source; find . -print0 | rsync -aHAXSv0 --files-from=- . user@host.dom:/dest

GNU cp(1) 和 openSSH scp(1):

# cd ./source; cp -a . /dest
# cd ./source; scp -pr . user@host.dom:/dest

GNU tar(1):

# (cd ./source && tar cf - . ) | (cd /dest && tar xvfp - )
# (cd ./source && tar cf - . ) | ssh user@host.dom '(cd /dest && tar xvfp - )'

cpio(1):

# cd ./source; find . -print0 | cpio -pvdm --null --sparse /dest

你能夠在所有包含 "." 的例子裡用 "foo" 替代 ".",這樣就可以從 "./source/foo" 目錄複製檔案到 "/dest/foo" 目錄。

You can substitute "." with the absolute path "/path/to/source/foo" for all examples containing "." to drop "cd ./source;". These copy files to different locations depending on tools used as follows.

  • "/dest/foo": rsync(8), GNU cp(1), 和 scp(1)

  • "/dest/path/to/source/foo": GNU tar(1), 和 cpio(1)

[提示] 提示

rsync(8) 和 GNU cp(1) 可以用 "-u" 選項來忽略接受端上更新的檔案。

find(1) is used to select files for archive and copy commands (see 第 10.1.3 节 “歸檔語法” and 第 10.1.4 节 “複製語法”) or for xargs(1) (see 第 9.3.9 节 “使用檔案迴圈來重複一個命令”). This can be enhanced by using its command arguments.

以下是 find(1)基本語法的總結。

  • find 條件引數的運算規則是從左到右。

  • This evaluation stops once its outcome is determined.

  • “邏輯 OR" (由條件之間的 "-o" 引數指定的)優先順序低於 "邏輯 AND" (由 "-a" 引數指定或者條件之間沒有任何引數)。

  • ”邏輯 NOT" (由條件前面的 "!" 指定) 優先順序高於 “邏輯 AND”。

  • "-prune" always returns logical TRUE and, if it is a directory, searching of file is stopped beyond this point.

  • "-name" matches the base of the filename with shell glob (see 第 1.5.6 节 “Shell 萬用字元”) but it also matches its initial "." with metacharacters such as "*" and "?". (New POSIX feature)

  • "-regex" matches the full path with emacs style BRE (see 第 1.6.2 节 “正則表達式”) as default.

  • "-size" matches the file based on the file size (value precedented with "+" for larger, precedented with "-" for smaller)

  • "-newer" 引數匹配比引數名中指定的檔案還要新的檔案。

  • "-print0" 引數總是返回邏輯 TRUE 並將完整檔名 (null terminated) 列印到標準輸出裝置上。

如下是 find(1) 語法格式。

# find /path/to \
    -xdev -regextype posix-extended \
    -type f -regex ".*\.cpio|.*~" -prune -o \
    -type d -regex ".*/\.git" -prune -o \
    -type f -size +99M -prune -o \
    -type f -newer /path/to/timestamp -print0

這些命令會執行如下動作。

  1. 查詢 "/path/to" 下的所有檔案

  2. Globally limit its search within its starting filesystem and uses ERE (see 第 1.6.2 节 “正則表達式”) instead

  3. Exclude files matching regex of ".*\.cpio" or ".*~" from search by stop processing

  4. Exclude directories matching regex of ".*/\.git" from search by stop processing

  5. Exclude files larger than 99 Megabytes (units of 1048576 bytes) from search by stop processing

  6. Print filenames which satisfy above search conditions and are newer than "/path/to/timestamp"

Please note the idiomatic use of "-prune -o" to exclude files in the above example.

[注意] 注意

對於非 Debian 系的 Unix-like 系統,有些引數可能不被 find(1) 命令所支援。在這種情況下,應該考慮調整匹配方法並用 "-print" 替代 "-print0"。你可能同樣需要更改其他相關的命令。

為重要的資料存檔尋找 儲存裝置 時,你應該注意它們的侷限性。對於小型的個人資料備份,我使用品牌公司的 CD-R 和 DVD-R 然後把它放在陰涼、乾燥、清潔的地方。(專業的一般使用磁帶存檔介質)

[注意] 注意

防火安全 是對於紙質文件來說的,大多數的計算機資料儲存媒介耐熱性比紙差。我經常依賴儲存在多個安全地點的加密拷貝。

網上(主要是來源於供應商資訊)可以檢視儲存介質的最大使用壽命。

  • 大於100年:用墨水的無酸紙

  • 100年:光碟儲存(CD/DVD,CD/DVD-R)

  • 30年:磁帶儲存(磁帶,軟盤)

  • 20年:相變光碟儲存(CD-RW)

這不包括由於人為導致的機械故障等等。

網上(主要來源於供應商資訊)可以檢視儲存介質的最大的寫次數。

  • 大於250,000次:硬碟驅動器

  • 大於10,000次:快閃記憶體

  • 1,000次:CD/DVD-RW

  • 1次:CD/DVD-R,紙

[小心] 小心

這裡的儲存壽命和寫次數的資料不應該被用來決定任何用於關鍵資料的儲存媒介,請翻閱製造商提供的特定產品的說明。

[提示] 提示

因為 CD/DVD-R 和 紙只能寫一次,它們從根本上阻止了因為重寫導致的資料意外丟失。這是優點!

[提示] 提示

如果你需要更快更頻繁的進行大資料備份,那麼通過高速網路連線的遠端主機上的硬碟來實現備份,可能是唯一可行的方法。

可移動儲存裝置可能是以下的任何一種。

它們可以通過以下的方式來進行連線。

像 GNOME 和 KDE 這樣的現代桌面環境能夠在 "/etc/fstab" 檔案中沒有匹配條目的時候,自動掛載這些可移動裝置。

  • udisks 包提供了守護程序和相關的實用程式來掛載和解除安裝這些裝置。

  • D-bus creates events to initiate automatic processes.

  • PolicyKit provides required privileges.

[提示] 提示

Automounted devices may have the "uhelper=" mount option which is used by umount(8).

[提示] 提示

只有當這些可移動裝置沒有在 "/etc/fstab" 檔案中列出時,桌面環境下才會自動掛載。

現代桌面環境下的掛載點被選為 "/media/<disk_label>",它可以被如下所示的來定製。

  • FAT 格式的檔案系統使用 mlabel(1) 命令

  • ISO9660 檔案系統使用帶有 "-V" 選項的 genisoimage(1) 命令

  • ext2/ext3/ext4 檔案系統使用帶有 "-L" 選項的 tune2fs(1) 命令

[提示] 提示

掛載時可能需要提供編碼選項(參見 第 8.3.6 节 “檔名編碼”)。

[提示] 提示

在圖形介面選單上移除檔案系統,可能會移除它的動態裝置節點例如 "/dev/sdc"。如果你想要保留它的裝置節點,你應該在命令列提示符上輸入 umount(8) 命令來解除安裝它。

當你通過可移動儲存裝置與其他系統分享資料的時候,你應該先把它格式化為被兩種作業系統都支援的通用的 檔案系統。下面是檔案系統的列表。


[提示] 提示

檢視第 9.8.1 节 “Removable disk encryption with dm-crypt/LUKS”來獲得關於使用裝置級加密的跨平臺的資料共享的資訊。

FAT 檔案系統被絕大多數的現代作業系統支援,它對於通過可行動硬碟進行的資料交換是非常有用的。

當格式化像裝有 FAT 檔案系統的跨平臺資料共享的可移動裝置時,以下應該是保險的選擇。

當使用 FAT 或 ISO9660 檔案系統分享資料時,如下是需要注意的安全事項。

  • tar(1),或cpio(1)命令壓縮檔案,目地是為了保留檔名,符號連結,原始的檔案許可權和檔案所有者資訊。

  • split(1) 命令把壓縮檔案分解成若干小於 2GiB的小檔案,使其免受檔案大小限制。

  • 加密壓縮檔案保護其內容免受未經授權的訪問。

[注意] 注意

因為 FAT 檔案系統的設計,最大的檔案大小為 (2^32 - 1) bytes = (4GiB -1 byte)。對於一些老舊的 32 位系統上的應用程式而言,最大的檔案大小甚至更小(2^31 -1) bytes = (2GiB -1 byte)。Debian 沒有遇到後者的問題。

[注意] 注意

微軟系統本身並不建議在超過 200MB 的分割槽或者驅動器上使用 FAT。他們的 " Overview of FAT, HPFS, and NTFS File Systems 這篇文章突出顯示了微軟系統的缺點,例如低效的磁碟空間利用。當然了,我們在 Linux 系統上還是應該使用 ext4 檔案系統。

[提示] 提示

有關檔案系統和訪問檔案系統的更多資訊,請參考 "Filesystems HOWTO"。

我們都熟知計算機有時會出問題,或者由於人為的錯誤導致系統和資料損壞。備份和恢復操作是成功的系統管理中非常重要的一部分。可能有一天你的電腦就會出問題。

[提示] 提示

保持你的備份系統簡潔並且經常備份你的系統,有備份資料比你採用的備份方法的技術先進要重要的多。

有3個關鍵的因素決定實際的備份和恢復策略。

  1. 知道要備份和恢復什麼。

    • 你自己建立的資料檔案:在 "~/" 下的資料

    • 你使用的應用程式建立的資料檔案:在 "/var/" 下的資料(除了 "/var/cache/","/var/run/" 和 "/var/tmp/")

    • 系統配置檔案:在 "/etc/” 下的資料

    • 本地軟體:在 "/usr/local/" 或 "/opt/" 下的資料

    • System installation information: a memo in plain text on key steps (partition, …)

    • Proven set of data: confirmed by experimental recovery operations in advance

  2. 知道怎樣去備份和恢復。

    • 安全的資料儲存:保護其免於覆蓋和系統故障

    • 經常備份:有計劃的備份

    • Redundant backup: data mirroring

    • Fool proof process: easy single command backup

  3. 評估涉及的風險和成本。

    • Value of data when lost

    • 備份所需的資源:人力,硬體,軟體,…

    • Failure mode and their possibility

[注意] 注意

除非你知道自己做的是什麼,否則不要備份 /proc, /sys, /tmp, 和 /run 目錄下的偽檔案系統(參見 第 1.2.12 节 “procfs 和 sysfs”第 1.2.13 节 “tmpfs”)。它們是龐大且無用的資料。

至於安全的資料儲存,資料至少是應該在不同的磁碟分割槽上最好是在不同的磁碟和機器上,來承受檔案系統發生的損壞。重要的資料最好儲存在只能寫一次的媒介上例如 CD/DVD-R 來防止覆蓋事故。(參見 第 9.7 节 “二進位制資料” 怎樣在 shell 命令列寫入儲存媒介。GNOME 桌面圖形環境可以讓你輕鬆的通過選單:“位置 → CD/DVD 燒錄”來實現寫入操作。)

[注意] 注意

當備份資料的時候,你可能希望停止一些應用程式的守護程序例如 MTA(參見第 6.3 节 “郵件傳輸代理 (MTA)”)。

[注意] 注意

你應該格外小心地備份和恢復身份認證相關的資料檔案例如 "/etc/ssh/ssh_host_dsa_key", "/etc/ssh/ssh_host_rsa_key", "~/.gnupg/*", "~/.ssh/*", /etc/passwd", "/etc/shadow", "/etc/fetchmailrc", "popularity-contest.conf", "/etc/ppp/pap-secrets" 和 "/etc/exim4/passwd.client/"。 這些資料中的有一些檔案是不能通過向系統輸入同樣的字串來再生的。

[注意] 注意

如果你以使用者程序的方式執行 cron job,你必須儲存檔案到 "/var/spool/cron/crontabs" 目錄並且重啟 cron(8)。參見第 9.3.14 节 “定時任務安排”來獲得關於 cron(8)crontab(1) 的資訊。

以下是 Debian 系統上值得注意的實用備份程式套件的列表。


備份工具有各自的專用的用途。

  • Mondo Rescue is a backup system to facilitate restoration of complete system quickly from backup CD/DVD etc. without going through normal system installation processes.

  • sbackupkeep 軟體包提供了易於桌面使用者使用的 GUI 前端,用於定期備份使用者資料。同樣的功能可以通過一個簡單的指令碼(第 10.2.2 节 “一個系統備份的指令碼例子”)和 cron(8) 來實現。

  • BaculaAmandaBackupPC 是全功能的備份實用套件,主要用於聯網的定期備份。

第 10.1.1 节 “存檔和壓縮工具”第 10.1.2 节 “複製和同步工具” 描述的基礎工具能夠通過自定義指令碼來幫助系統備份。這些指令碼的功能可以通過如下的工具來增強。

  • obnam 軟體包能夠增量備份(遠端)。

  • rdiff-backup 軟體包能夠增量備份(遠端)。

  • The dump package helps to archive and restore the whole filesystem incrementally and efficiently.

[提示] 提示

參見 "/usr/share/doc/dump/" 和 "Is dump really deprecated?" 來了解 dump 程式。

對於執行 unstable 套件的個人 Debian 桌面系統來說,只需要保護個人資料和關鍵資料。我不管怎樣每年都會重新安裝一次系統。因此沒理由去備份整個系統或者安裝全功能的備份實用程式。

我使用簡單的指令碼來製作用於備份的壓縮檔案並用 GUI 介面把它燒寫到 CD/DVD 裡。以下是關於這個的指令碼例子。

#!/bin/sh -e
# Copyright (C) 2007-2008 Osamu Aoki <osamu@debian.org>, Public Domain
BUUID=1000; USER=osamu # UID and name of a user who accesses backup files
BUDIR="/var/backups"
XDIR0=".+/Mail|.+/Desktop"
XDIR1=".+/\.thumbnails|.+/\.?Trash|.+/\.?[cC]ache|.+/\.gvfs|.+/sessions"
XDIR2=".+/CVS|.+/\.git|.+/\.svn|.+/Downloads|.+/Archive|.+/Checkout|.+/tmp"
XSFX=".+\.iso|.+\.tgz|.+\.tar\.gz|.+\.tar\.bz2|.+\.cpio|.+\.tmp|.+\.swp|.+~"
SIZE="+99M"
DATE=$(date --utc +"%Y%m%d-%H%M")
[ -d "$BUDIR" ] || mkdir -p "BUDIR"
umask 077
dpkg --get-selections \* > /var/lib/dpkg/dpkg-selections.list
debconf-get-selections > /var/cache/debconf/debconf-selections

{
find /etc /usr/local /opt /var/lib/dpkg/dpkg-selections.list \
     /var/cache/debconf/debconf-selections -xdev -print0
find /home/$USER /root -xdev -regextype posix-extended \
  -type d -regex "$XDIR0|$XDIR1" -prune -o -type f -regex "$XSFX" -prune -o \
  -type f -size  "$SIZE" -prune -o -print0
find /home/$USER/Mail/Inbox /home/$USER/Mail/Outbox -print0
find /home/$USER/Desktop  -xdev -regextype posix-extended \
  -type d -regex "$XDIR2" -prune -o -type f -regex "$XSFX" -prune -o \
  -type f -size  "$SIZE" -prune -o -print0
} | cpio -ov --null -O $BUDIR/BU$DATE.cpio
chown $BUUID $BUDIR/BU$DATE.cpio
touch $BUDIR/backup.stamp

這是一個用 root 許可權執行的指令碼例子。

我建議你按照如下所示的去更改和執行這個指令碼。

把事情簡單化!

[提示] 提示

You can recover debconf configuration data with "debconf-set-selections debconf-selections" and dpkg selection data with "dpkg --set-selection <dpkg-selections.list".

對於目錄樹下面的資料集,"cp -a" 命令可以實現常規備份。

For the set of large non-overwritten static data under a directory tree such as the one under the "/var/cache/apt/packages/" directory, hardlinks with "cp -al" provide an alternative to the normal backup with efficient use of the disk space.

以下是一個用於資料備份的名為 bkup 的複製指令碼。它把當前目錄下的所有 (non-VCS) 檔案複製到父目錄下的指定目錄中或者遠端主機上。

#!/bin/sh -e
# Copyright (C) 2007-2008 Osamu Aoki <osamu@debian.org>, Public Domain
fdot(){ find . -type d \( -iname ".?*" -o -iname "CVS" \) -prune -o -print0;}
fall(){ find . -print0;}
mkdircd(){ mkdir -p "$1";chmod 700 "$1";cd "$1">/dev/null;}
FIND="fdot";OPT="-a";MODE="CPIOP";HOST="localhost";EXTP="$(hostname -f)"
BKUP="$(basename $(pwd)).bkup";TIME="$(date  +%Y%m%d-%H%M%S)";BU="$BKUP/$TIME"
while getopts gcCsStrlLaAxe:h:T f; do case $f in
g)  MODE="GNUCP";; # cp (GNU)
c)  MODE="CPIOP";; # cpio -p
C)  MODE="CPIOI";; # cpio -i
s)  MODE="CPIOSSH";; # cpio/ssh
t)  MODE="TARSSH";; # tar/ssh
r)  MODE="RSYNCSSH";; # rsync/ssh
l)  OPT="-alv";; # hardlink (GNU cp)
L)  OPT="-av";;  # copy (GNU cp)
a)  FIND="fall";; # find all
A)  FIND="fdot";; # find non CVS/ .???/
x)  set -x;; # trace
e)  EXTP="${OPTARG}";; # hostname -f
h)  HOST="${OPTARG}";; # user@remotehost.example.com
T)  MODE="TEST";; # test find mode
\?) echo "use -x for trace."
esac; done
shift $(expr $OPTIND - 1)
if [ $# -gt 0 ]; then
  for x in $@; do cp $OPT $x $x.$TIME; done
elif [ $MODE = GNUCP ]; then
  mkdir -p "../$BU";chmod 700 "../$BU";cp $OPT . "../$BU/"
elif [ $MODE = CPIOP ]; then
  mkdir -p "../$BU";chmod 700 "../$BU"
  $FIND|cpio --null --sparse -pvd ../$BU
elif [ $MODE = CPIOI ]; then
  $FIND|cpio -ov --null | ( mkdircd "../$BU"&&cpio -i )
elif [ $MODE = CPIOSSH ]; then
  $FIND|cpio -ov --null|ssh -C $HOST "( mkdircd \"$EXTP/$BU\"&&cpio -i )"
elif [ $MODE = TARSSH ]; then
  (tar cvf - . )|ssh -C $HOST "( mkdircd \"$EXTP/$BU\"&& tar xvfp - )"
elif [ $MODE = RSYNCSSH ]; then
  rsync -aHAXSv ./ "${HOST}:${EXTP}-${BKUP}-${TIME}"
else
  echo "Any other idea to backup?"
  $FIND |xargs -0 -n 1 echo
fi

This is meant to be command examples. Please read script and edit it by yourself before using it.

[提示] 提示

I keep this bkup in my "/usr/local/bin/" directory. I issue this bkup command without any option in the working directory whenever I need a temporary snapshot backup.

[提示] 提示

For making snapshot history of a source file tree or a configuration file tree, it is easier and space efficient to use git(7) (see 第 10.6.5 节 “記錄配置歷史的 Git”).

資料安全基礎設施是資料加密,訊息摘要和簽名工具的結合。


See 第 9.8 节 “資料加密提示” on dm-crypto and ecryptfs which implement automatic data encryption infrastructure via Linux kernel modules.

如下是 GNU 隱私衛士 基本的金鑰管理命令。


Here is the meaning of the trust code.


如下命令上傳我的 "1DD8D791" 公鑰到主流的公鑰伺服器 "hkp://keys.gnupg.net"。

$ gpg --keyserver hkp://keys.gnupg.net --send-keys 1DD8D791

預設良好的公鑰伺服器在 "~/.gnupg/gpg.conf" (舊的位置在 "~/.gnupg/options")檔案中設定,此檔案包含了以下資訊。

keyserver hkp://keys.gnupg.net

The following obtains unknown keys from the keyserver.

$ gpg --list-sigs --with-colons | grep '^sig.*\[User ID not found\]' |\
  cut -d ':' -f 5| sort | uniq | xargs gpg --recv-keys

There was a bug in OpenPGP Public Key Server (pre version 0.9.6) which corrupted key with more than 2 sub-keys. The newer gnupg (>1.2.1-2) package can handle these corrupted subkeys. See gpg(1) under "--repair-pks-subkey-bug" option.

md5sum(1) 提供了製作摘要檔案的一個工具,它使用 rfc1321 裡的方式製作摘要檔案.

$ md5sum foo bar >baz.md5
$ cat baz.md5
d3b07384d113edec49eaa6238ad5ff00  foo
c157a79031e1c40f85931829bc5fc552  bar
$ md5sum -c baz.md5
foo: OK
bar: OK
[注意] 注意

MD5 校驗和的 CPU 計算強度是比 GNU Privacy Guard (GnuPG) 加密簽名要少的.在通常情況下,只有頂級的摘要檔案才需要加密簽名來確保資料完整性.

這裡有許多原始碼合併工具。如下的是我感興趣的工具。

表 10.10. 原始碼合併工具列表

軟件包 流行度 大小 命令 說明
diffutils V:856, I:978 1327 diff(1) 逐行比較兩個檔案
diffutils V:856, I:978 1327 diff3(1) 逐行比較和合並三個檔案
vim V:118, I:393 2374 vimdiff(1) 在 vim 中並排比較兩個檔案
patch V:100, I:928 216 patch(1) 給原檔案打補丁
dpatch V:1, I:17 191 dpatch(1) 管理 Debian 軟體包的系列補丁
diffstat V:20, I:188 70 diffstat(1) produce a histogram of changes by the diff
patchutils V:19, I:180 223 combinediff(1) create a cumulative patch from two incremental patches
patchutils V:19, I:180 223 dehtmldiff(1) extract a diff from an HTML page
patchutils V:19, I:180 223 filterdiff(1) extract or excludes diffs from a diff file
patchutils V:19, I:180 223 fixcvsdiff(1) fix diff files created by CVS that patch(1) mis-interprets
patchutils V:19, I:180 223 flipdiff(1) exchange the order of two patches
patchutils V:19, I:180 223 grepdiff(1) show which files are modified by a patch matching a regex
patchutils V:19, I:180 223 interdiff(1) show differences between two unified diff files
patchutils V:19, I:180 223 lsdiff(1) show which files are modified by a patch
patchutils V:19, I:180 223 recountdiff(1) recompute counts and offsets in unified context diffs
patchutils V:19, I:180 223 rediff(1) fix offsets and counts of a hand-edited diff
patchutils V:19, I:180 223 splitdiff(1) separate out incremental patches
patchutils V:19, I:180 223 unwrapdiff(1) demangle patches that have been word-wrapped
wiggle V:0, I:0 166 wiggle(1) apply rejected patches
quilt V:4, I:44 711 quilt(1) manage series of patches
meld V:13, I:42 3049 meld(1) compare and merge files (GTK)
dirdiff V:0, I:3 144 dirdiff(1) display differences and merge changes between directory trees
docdiff V:0, I:0 573 docdiff(1) compare two files word by word / char by char
imediff2 V:0, I:0 34 imediff2(1) interactive full screen 2-way merge tool
makepatch V:0, I:0 102 makepatch(1) generate extended patch files
makepatch V:0, I:0 102 applypatch(1) apply extended patch files
wdiff V:5, I:85 643 wdiff(1) display word differences between text files

Here is a summary of the version control systems (VCS) on the Debian system.

[注意] 注意

If you are new to VCS systems, you should start learning with Git, which is growing fast in popularity.


VCS is sometimes known as revision control system (RCS), or software configuration management (SCM).

Distributed VCS such as Git is the tool of choice these days. CVS and Subversion may still be useful to join some existing open source program activities.

Debian provides free VCS services via Debian Alioth service. It supports practically all VCSs. Its documentation can be found at http://wiki.debian.org/Alioth .

There are few basics for creating a shared access VCS archive.

Here is an oversimplified comparison of native VCS commands to provide the big picture. The typical command sequence may require options and arguments.


[小心] 小心

Invoking a git subcommand directly as "git-xyz" from the command line has been deprecated since early 2006.

[提示] 提示

If there is a executable file git-foo in the path specified by $PATH, entring "git foo" without hyphen to the command line invokes this git-foo. This is a feature of the git command.

[提示] 提示

GUI tools such as tkcvs(1) and gitk(1) really help you with tracking revision history of files. The web interface provided by many public archives for browsing their repositories is also quite useful, too.

[提示] 提示

Git can work directly with different VCS repositories such as ones provided by CVS and Subversion, and provides the local repository for local changes with git-cvs and git-svn packages. See git for CVS users, and 第 10.6.4 节 “用於 Subversion 倉庫的 Git”.

[提示] 提示

Git has commands which have no equivalents in CVS and Subversion: "fetch", "rebase", "cherry-pick", …

Git 可以用來做本地和遠程源代碼管理的任何事情。這意味着,你能夠在本地記錄源代碼修改,而不是必須要和遠程倉庫有網絡連接。

看下面。

git-gui(1)gitk(1) 命令使 Git 變得非常容易使用。

[警告] 警告

不要使用帶空格的標簽字符串。即使一些工具,如 gitk(1) 允許你使用它,但會阻礙其它 git 命令。

即使你的上游使用不同的版本控制系統,使用 git(1) 作爲本地活動的版本控制系統,仍然是一個好的主意,因爲 git 可以讓你在沒有上遊網絡連接的情況下,管理你的本地源代碼樹拷貝。這裏有一些 git(1) 使用的包和命令。


[提示] 提示

With git(1), you work on a local branch with many commits and use something like "git rebase -i master" to reorganize change history later. This enables you to make clean change history. See git-rebase(1) and git-cherry-pick(1).

[提示] 提示

When you want to go back to a clean working directory without loosing the current state of the working directory, you can use "git stash". See git-stash(1).

你可以使用 Git 工具來手工記錄按時間先後順序的配置歷史。這裏是一個例子,讓你練習記錄"/etc/apt/" 內容。

$ cd /etc/apt/
$ sudo git init
$ sudo chmod 700 .git
$ sudo git add .
$ sudo git commit -a

提交配置,描述此次提交。

對配置文件進行修改。

$ cd /etc/apt/
$ sudo git commit -a

提交配置,說明提交,繼續你的工作。

$ cd /etc/apt/
$ sudo gitk --all

你有全部的配置歷史。

[注意] 注意

sudo(8) 是需要用於配置數據文件,任意文件權限的情況。 對於普通用戶的配置數據,你需要省略 sudo

[注意] 注意

在上面例子裏的 "chmod 700 .git" 命令,是用來保護文檔數據不被未經授權的讀訪問。

[提示] 提示

要更加完整的建立配置歷史記錄,請參閱 etckeeper 包: 第 9.2.10 节 “記錄配置檔案的變更”

看下面。

  • cvs(1)

  • "/usr/share/doc/cvs/html-cvsclient"

  • "/usr/share/doc/cvs/html-info"

  • "/usr/share/doc/cvsbook"

  • "info cvs"

Many public CVS servers provide read-only remote access to them with account name "anonymous" via pserver service. For example, Debian web site contents are maintained by webwml project via CVS at Debian alioth service. The following sets up "$CVSROOT" for the remote access to this CVS repository.

$ export CVSROOT=:pserver:anonymous@anonscm.debian.org:/cvs/webwml
$ cvs login
[注意] 注意

Since pserver is prone to eavesdropping attack and insecure, write access is usually disable by server administrators.

The following sets up "$CVS_RSH" and "$CVSROOT" for the remote access to the CVS repository by webwml project with SSH.

$ export CVS_RSH=ssh
$ export CVSROOT=:ext:account@cvs.alioth.debian.org:/cvs/webwml

You can also use public key authentication for SSH which eliminates the remote password prompt.

Here is an example of typical work flow using CVS.

Check all available modules from CVS project pointed by "$CVSROOT" by the following.

$ cvs rls
CVSROOT
module1
module2
...

Checkout "module1" to its default directory "./module1" by the following.

$ cd ~/path/to
$ cvs co module1
$ cd module1

按需修改裡面的內容。

通過如下所示的命令來檢查改變,其作用相當於使用 "diff -u [repository] [local]"。

$ cvs diff -u

你發現自己改壞了 "file_to_undo" 檔案,而其他的檔案都是好的。

Overwrite "file_to_undo" file with the clean copy from CVS by the following.

$ cvs up -C file_to_undo

Save the updated local source tree to CVS by the following.

$ cvs ci -m "Describe change"

Create and add "file_to_add" file to CVS by the following.

$ vi file_to_add
$ cvs add file_to_add
$ cvs ci -m "Added file_to_add"

Merge the latest version from CVS by the following.

$ cvs up -d

當心以 "C filename" 開頭的行,這意味著衝突的改變。

Look for unmodified code in ".#filename.version".

查詢檔案中的 "<<<<<<<" 和 ">>>>>>>" 來獲得衝突的改變的資訊。

按需更改檔案來解決衝突。

按如下所示新增一個釋出標籤 "Release-1"。

$ cvs ci -m "last commit for Release-1"
$ cvs tag Release-1

繼續編輯檔案。

按如下所示移除釋出分支 "Release-1"。

$ cvs tag -d Release-1

Check in changes to CVS by the following.

$ cvs ci -m "real last commit for Release-1"

Re-add the release tag "Release-1" to updated CVS HEAD of main by the following.

$ cvs tag Release-1

Create a branch with a sticky branch tag "Release-initial-bugfixes" from the original version pointed by the tag "Release-initial" and check it out to "~/path/to/old" directory by the following.

$ cvs rtag -b -r Release-initial Release-initial-bugfixes module1
$ cd ~/path/to
$ cvs co -r Release-initial-bugfixes -d old module1
$ cd old
[提示] 提示

Use "-D 2005-12-20" (ISO 8601 date format) instead of "-r Release-initial" to specify particular date as the branch point.

Work on this local source tree having the sticky tag "Release-initial-bugfixes" which is based on the original version.

獨自在 "Release-initial-bugfixes" 分支上工作...直到有其他人加入到此分支。

Sync with files modified by others on this branch while creating new directories as needed by the following.

$ cvs up -d

按需更改檔案來解決衝突。

Check in changes to CVS by the following.

$ cvs ci -m "checked into this branch"

Update the local tree by HEAD of main while removing sticky tag ("-A") and without keyword expansion ("-kk") by the following.

$ cvs up -d -kk -A

Update the local tree (content = HEAD of main) by merging from the "Release-initial-bugfixes" branch and without keyword expansion by the following.

$ cvs up -d -kk -j Release-initial-bugfixes

用編輯器來解決衝突。

Check in changes to CVS by the following.

$ cvs ci -m "merged Release-initial-bugfixes"

按如下所示建立歸檔。

$ cd ..
$ mv old old-module1-bugfixes
$ tar -cvzf old-module1-bugfixes.tar.gz old-module1-bugfixes
$ rm -rf old-module1-bugfixes
[提示] 提示

"cvs up" command can take "-d" option to create new directories and "-P" option to prune empty directories.

[提示] 提示

You can checkout only a sub directory of "module1" by providing its name as "cvs co module1/subdir".


Subversion is a recent-generation version control system replacing older CVS. It has most of CVS's features except tags and branches.

你需要安裝 subversionlibapache2-svnsubversion-tools 軟體包來搭建 Subversion 伺服器。

這裡給出使用 Subversion 及其原生客戶端的典型工作流示例。

[提示] 提示

Client commands offered by the git-svn package may offer alternative work flow of Subversion using the git command. See 第 10.6.4 节 “用於 Subversion 倉庫的 Git”.

檢視如下所示的 URL "file:///srv/svn/project" 指向的 Subversion 專案上所有可用的模組。

$ svn list file:///srv/svn/project
module1
module2
...

按如下所示的簽出 "module1/trunk" 到 "module1" 目錄。

$ cd ~/path/to
$ svn co file:///srv/svn/project/module1/trunk module1
$ cd module1

按需修改裡面的內容。

通過如下所示的命令來檢查改變,其作用相當於使用 "diff -u [repository] [local]"。

$ svn diff

你發現自己改壞了 "file_to_undo" 檔案,而其他的檔案都是好的。

按如下所示的用 Subversion 中的乾淨副本來覆蓋 "file_to_undo" 檔案。

$ svn revert file_to_undo

按如下所示的把已經更新了的本地源目錄樹儲存到 Subversion。

$ svn ci -m "Describe change"

按如下所示的建立 "file_to_add" 檔案並把它新增到 Subversion。

$ vi file_to_add
$ svn add file_to_add
$ svn ci -m "Added file_to_add"

按如下所示更新工作拷貝到 Subversion 中的最新版本。

$ svn up

當心以 "C filename" 開頭的行,這意味著衝突的改變。

檢視檔案中未經修改的程式碼,例如 "filename.r6", "filename.r9" 和 "filename.mine" 檔案。

查詢檔案中的 "<<<<<<<" 和 ">>>>>>>" 來獲得衝突的改變的資訊。

按需更改檔案來解決衝突。

按如下所示新增一個釋出標籤 "Release-1"。

$ svn ci -m "last commit for Release-1"
$ svn cp file:///srv/svn/project/module1/trunk file:///srv/svn/project/module1/tags/Release-1

繼續編輯檔案。

按如下所示移除釋出分支 "Release-1"。

$ svn rm file:///srv/svn/project/module1/tags/Release-1

按如下所示把改變簽入到 Subversion。

$ svn ci -m "real last commit for Release-1"

按如下所示在最新的 Subversion 主幹的基礎上重新添加發布分支 "Release-1"。

$ svn cp file:///srv/svn/project/module1/trunk file:///srv/svn/project/module1/tags/Release-1

按如下所示在 "module1/tags/Release-initial" 路徑指定的最初版本的基礎上再建立一個路徑為 "module1/branches/Release-initial-bugfixes" 的分支,並把它簽出到 "~/path/to/old" 目錄。

$ svn cp file:///srv/svn/project/module1/tags/Release-initial file:///srv/svn/project/module1/branches/Release-initial-bugfixes
$ cd ~/path/to
$ svn co file:///srv/svn/project/module1/branches/Release-initial-bugfixes old
$ cd old
[提示] 提示

Use "module1/trunk@{2005-12-20}" (ISO 8601 date format) instead of "module1/tags/Release-initial" to specify particular date as the branch point.

在基於原始版本的 "Release-initial-bugfixes" 分支的本地源目錄樹上工作。

獨自在 "Release-initial-bugfixes" 分支上工作...直到有其他人加入到此分支。

按如下所示同步其他人在此分支上改動的檔案。

$ svn up

按需更改檔案來解決衝突。

按如下所示把改變簽入到 Subversion。

$ svn ci -m "checked into this branch"

按如下所示更新本地目錄樹為主幹的最新版本。

$ svn switch file:///srv/svn/project/module1/trunk

按如下所示通過合併 "Release-initial-bugfixes" 分支的方式來更新本地目錄樹 (內容為主幹的最新版本)。

$ svn merge file:///srv/svn/project/module1/branches/Release-initial-bugfixes

用編輯器來解決衝突。

按如下所示把改變簽入到 Subversion。

$ svn ci -m "merged Release-initial-bugfixes"

按如下所示建立歸檔。

$ cd ..
$ mv old old-module1-bugfixes
$ tar -cvzf old-module1-bugfixes.tar.gz old-module1-bugfixes
$ rm -rf old-module1-bugfixes
[提示] 提示

你能夠用像 "http://…" 和 "svn+ssh://..." 這樣格式的 URL 來替代 "file:///…" URL。

[提示] 提示

通過 "svn co file:///srv/svn/project/module1/trunk/subdir module1/subdir" 等命令,你可以只簽出 "module1" 的一個子目錄。