3.2. unison 命令
3.2.1. unison 命令行
3.2.2. 常用参数
3.2.3. 模式匹配
3.2.4. 应用举例
3.2.5. unison 配置文件
3.2.6. FAQ
Unison 是一个文件同步工具,采用 rsync 类似的算法,但是提高了一步,双向同步以及一个统一的版本控制系统。
3.2.1. unison 命令行
可以用如下格式调用 unison
unison profile_name [options]
读取 ~/.unison 目录下的配置文件 "profile_name.prf"。
注意到命令行没有指出要进行文件同步的两个地址,实际上应该在配置文件
中有相关的 root 指令进行了设置。如:
# Roots of the synchronization
root = /home/bcpierce
root = ssh://saul//home/bcpierce
# Paths to synchronize
path = current
path = common
path = .netscape/bookmarks.html
unison profile root1 root2 [options]
root1, root2 分别是要执行同步的两个路径。这时 "profile.prf" 配置文件中,应该不包含 root 设置;
root1, root2 路径的格式可以是本地目录,也可以是远程服务器的路径,例如: ssh://username@remotehost//home/jiangxin/work
unison root1 root2 [options]
相当于 unison default root1 root2。即读取 "default.prf" 的配置。
3.2.2. 常用参数
-testserver
测试连通性,连接到服务器即退出。示例:
$ unison / ssh://opensou1@bluehost/ -servercmd=~/bin/unison -testserver
如果服务器端 unison 可执行文件不在默认目录下,甚至没有 unison 命令(需要你编译一个上传到服务器),则需要使用 -servercmd 参数告诉要执行的服务器 unison 命令位置。
使用 -testserver 参数,则成功链接即退出,也不会去执行目录的比较等后续操作。
-servercmd xxx
告诉 unison, 服务器端的 unison 命令是什么。参见上面的示例。
-auto
接受缺省的动作,然后等待用户确认是否执行。
-batch
batch mode, 全自动模式,接受缺省动作,并执行。
-ignore xxx
增加 xxx 到忽略列表中
-ignorecase [true|false|default]
是否忽略文件名大小写
-follow xxx
是否支持对符号连接指向内容的同步;
例如在我的 ~/.unison 的配置文件 default.prf 中有
# Unison preferences file
follow = Path {unison_*}
ignore = Path {WWWROOT/wiki_mirror}
ignore = Name {,.}*{.~$lock}
ignore = Name {a.out}
我将预进行同步的系统文件在 xxx/src 下分别作符号链接,如 unison_httpd.conf 指向 c:/program files/apache/.../httpd.conf。 同步时,"follow = Path {unison_*}" 配置(或参数)将跟踪符号链接指向的实际文件。 如果没有该设置,符号链接不予同步。
-immutable xxx
不变目录,扫描时即忽略
-silent
安静模式
-times
同步修改时间
-path xxx 参数
只同步 -path 参数指定的子目录以及文件,而非整个目录。例如
unison /home/username ssh://remotehost//home/username \
-path shared \
-path pub \
-path .netscape/bookmarks.html
3.2.3. 模式匹配
如下参数 ignore/ignorenot, follow, sortfirst/sortlast, backup, merge 定义各自的匹配模式。例如: ignore = pattern
pattern 的语法格式
Regex regexp
即常规表达式。
Name name
路径的最后一部分与 “name" 匹配。可以使用通配符,见下面描述。
Path path
全路径与 "path" 匹配。可以使用通配符,见下面描述。
以下通配符可以用在 Path 和 Name 中:
?
匹配除了 "/" 之外,任意单个字符;
*
匹配除了 "/" 之外的任意字符;如果用在 "Name" 中,则不和以 "."开始的文件匹配,而用在 "Path" 中,可以和 "." 开始的向匹配。
[xyz]
匹配 {x,y,z} 中任一字符;
{a,bb,ccc}
匹配 a, bb, ccc 中任何一个;
示例:
忽略 CVS 目录以及以 .cmo 结尾的文件:
ignore = Name {CVS,*.cmo}
忽略路径 a/b:
ignore = Path a/b
忽略路径 */tmp。当 * 用在 Path 中,可以和以 "." 开始的文件、目录名匹配,如下面的和 ".foo/tmp" 匹配;
ignore = Path */tmp
忽略 a/b/ 开始,结尾是 .ml 的文件。
ignore = Regex a/b/.*\.ml
3.2.4. 应用举例
本地目录间的镜像
unison <目录1> <目录2>
获取远程 unison 版本
ssh remotehostname unison -version
测试
unison -testServer 本地目录 ssh://user@remotehostname/远程目录
执行数据同步
unison <本地目录> ssh://remotehostname/<远程目录>
远程目录是绝对目录,不是用户主目录
注意 在主机和目录间又多加了一个 "/":
unison <本地目录> ssh://remotehostname//<绝对路径>
参数 -path 指定同步的子目录。以下只同步 /home/username 下的 shared 目录。
unison /home/username ssh://remotehost//home/username -path shared
-path 可以多次出现
unison /home/username ssh://remotehost//home/username \
-path shared \
-path pub \
-path .netscape/bookmarks.html
3.2.5. unison 配置文件
3.2.5.1. .unison 目录
~/.unison 目录保存用户配置文件以及 Archive 文件。
配置文件扩展名为 .prf,缺省的配置文件为: "default.prf"。
Archive 文件可能有多个,每对同步的对象对应一个文件。这个文件记录了文件的状态,可以在后续的更新动作中更快速的判断文件的更新动作。 Archive 文件名和双方的主机名、路径名等相关。
Archive 虽然自动由 unison 维护,但是特殊情况下(如本机的地址经常变更),可以利用下面的方法:
环境变量 "UNISONLOCALHOSTNAME" 可以用于本机地址经常变化的环境,unison 会采用该环境变量的值;
可以在缺省的配置文件中,用 rootalias 命令将新的主机、路径名称对应为老的主机名和路径名, 然后再确定出 archive 名称。这样就不会造成由于主机名修改,导致 unison 更新状态的丢失, 进而导致上次更新状态的丢失。
rootalias = //new-hostname//new-path -> //old-hostname//old-path
3.2.5.2. *.prf 配置文件
如果 unison 只带一个参数执行,如
unison
则在 ~/.unison 目录下查找 ".prf" 配置文件。
如果不带参数执行 unison,则查找 "default.prf" 文件。
3.2.5.3. .prf 文件示例
简单的 default.prf 示例
# Roots of the synchronization
root = /home/bcpierce
root = ssh://saul//home/bcpierce
# Paths to synchronize
path = current
path = common
path = .netscape/bookmarks.html
更复杂的配置文件:
# Roots of the synchronization
root = /home/bcpierce
root = ssh://saul//home/bcpierce
# Paths to synchronize
path = current
path = common
path = .netscape/bookmarks.html
# Some regexps specifying names and paths to ignore
ignore = Name temp.*
ignore = Name *~
ignore = Name .*~
ignore = Path */pilot/backup/Archive_*
ignore = Name *.o
ignore = Name *.tmp
# Window height
height = 37
# Keep a backup copy of the entire replica
backup = Name *
# Use this command for displaying diffs
diff = diff -y -W 79 --suppress-common-lines
# Log actions to the terminal
log = true
使用 include 包含文件
"unison workingset" 参照 "workingset.prf" 执行:
path = current/papers
path = Mail/inbox
path = Mail/drafts
include common
"common" 文件内容:
在 common 包含文件中,没有出现 PATH,毕竟要在包含文件中包含各个配置文件的交集么。
# Roots of the synchronization
root = /home/bcpierce
root = ssh://saul//home/bcpierce
# (... other preferences ...)
# If any new preferences are added by Unison (e.g. ’ignore’
# preferences added via the graphical UI), then store them in the
# file ’common’ rathen than in the top-level preference file
addprefsto = common
# regexps specifying names and paths to ignore
ignore = Name temp.*
ignore = Name *~
ignore = Name .*~
ignore = Path */pilot/backup/Archive_*
ignore = Name *.o
ignore = Name *.tmp
3.2.6. FAQ
3.2.6.1. ssh 超时问题
和远程服务器同步大量数据,上传一部分数据后,超时:
9% 559:15 ETARead from remote host bluehost: Connection reset by peer
Fatal error: Lost connection with the server
Google 搜索类似问题:
该文章提出增大 ssh 超时时间设置:
hello users, I am trying to run unison to sync up 2 different servers.
The directory I am syncing is pretty large... about 3000 subdirs and
each of those subdirs has a couple dozen dirs under them. About 80 GBs
of data total.
I am using the following command:
unison -batch /dir/path ssh://remoteserver//dir/path
I originally used rsync to move the directory over to the remote
server however I now have a need for bidirectional mirroring hence the
reason why I now use unison.
When I run this command, I get the usual warning about no prior index
found since this is the first run.
Unison then begins to list all the dirs and subdirs (building the
index dbase I suppose). When it's almost finished, I get the following
lines:
Waiting for changes from server
Fatal Error: Lost connection with server
I have used unison before to mirror directories between these two
machines, but none of which were this big with so many subdir branches.
Nothing in any logs to give me any clues. I though it might be some
sort of ssh timeout, so I added "ConnectTimeout 10" in
/etc/ssh/ssh_config to give it a 10 second timeout, but I dont think
this will help since the ssh session does indeed connect initially.
ulimit -s shows I have an 8MB stack size.
Can anyone shed any light onto this problem?
Thank you
另外一个用户提出将一个任务分解成多个任务的方法:
The connection between the client and the server can remain idle for a
long time when checking for updates. So, if there is a masquerading
router (or a firewall using stateful inspection) between the client
and the server, it may wrongly consider that the connection is dead
after some time.
The usual workaround is to use the path directive to synchronize
smaller parts of the replica at a time. This should necessary only
for the first synchronization, as the subsequent ones are much faster.
You could also try to use the ServerAliveInterval directive of ssh in
order to keep the connection active.