我想使用 crontab 同步我的 Linux 分区和 Windows 分区之间的两个目录,如下所示:
24 9 * * * cp -r /home/fan/Data /media/T/Data
但它会在原始 Data 目录中创建一个名为 Data 的目录,而不是从源目录复制丢失的文件。我在 cp 手册中找不到合适的选项来完美解决这个问题。我如何将丢失的文件(它们确实存在于目标目录中)从 src 复制到 dir。
顺便说一句,似乎需要挂载T盘才能运行复制命令,当我需要运行命令时如何自动挂载磁盘(挂载命令应以root身份运行)。
如果命令出现异常,我如何获取错误消息?
答案1
用于同步数据的转到工具是rsync
。您可以在目录级别同步或仅同步目录的内容,如下所示:
例子
目录同步24 9 * * * rsync -a /home/fan/Data /media/T/
内容同步
24 9 * * * rsync -a /home/fan/Data/ /media/T/Data/
第一个示例将目录Data
从同步/home/fan
到目录/media/T
。第二个示例将 的内容同步Data
到目录/media/T/Data
。
作为附加提示,我将使用以下表示法同步到目标目录:
24 9 * * * rsync -a /home/fan/Data/ /media/T/Data/.
/.
在阅读我的rsync
命令时,我发现更加明显。
行为示例
使用rsync
可能是我在培训新用户时遇到的最困惑的问题之一。
样本数据:
$ tree home/fan/Data/
home/fan/Data/
|-- file1
|-- file2
|-- file3
|-- file4
`-- file5
1.同步dir Data的内容
$ rsync -a home/fan/Data/ media/T/
请注意,我们将 的内容放入Data
中T
。
$ tree media/T/
media/T/
|-- file1
|-- file2
|-- file3
|-- file4
`-- file5
0 directories, 5 files
2.同步目录
$ rsync -a home/fan/Data media/T/
请注意,我们将目录Data
放入T
.
$ tree media/T/
media/T/
`-- Data
|-- file1
|-- file2
|-- file3
|-- file4
`-- file5
1 directory, 5 files
答案2
使用rsync
:
24 9 * * * rsync -a /home/fan/Data/ /media/T/Data
/
在源目录名称末尾添加额外内容将告诉rsync
您复制内容而不是完整目录。rsync
还将避免复制具有相同时间戳/大小的文件(即在 99.99% 的情况下不需要复制的文件)。
如果您要在同一系统上同步文件,还可以考虑使用--inplace
选项来rsync
加快速度。从手册页:
--inplace
This option changes how rsync transfers a file when its data needs to be
updated: instead of the default method of creating a new copy of the file and
moving it into place when it is complete, rsync instead writes the updated
data directly to the destination file.
不过,此选项有利有弊,最大的缺点可能是,如果同步中断,目标文件将处于不一致的状态,只能通过重新开始来修复。
答案3
要解决问题的错误消息部分,您可以选择从 cron 而不是系统命令运行脚本。
24 9 * * * /usr/local/sbin/sync_data.sh
创建文件为/usr/local/sbin/sync_data.sh
,授予 root 所有权和执行权限:chown root:root /usr/local/sbin/sync_data.sh && chmod 0700 /usr/local/sbin/sync_data.sh
。脚本的内容如下。
#!/usr/bin/env bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root." 1>&2
exit 1
fi
# [ ] vs [[ ]] : http://mywiki.wooledge.org/BashFAQ/031
dir_src="/home/fan/Data/"
dir_dst="/media/T/"
# A Boolean to know if running interactively or not
b_interactive=1
if [[ -v PS1 ]] ; then # The "-v PS1" method is for BASH 4.2+
$b_interactive=0 # Could also use [[ -z "$PS1" ]]
fi
# Send messages to console or syslog.
function notify() {
message="$1"
if [[ $b_interactive -eq 1 ]] ; then
echo "$message"
else
# eval combines args into a single string for execution...
eval $cmd_logger -p err "$0: $message"
fi
}
# If the mount point if not currently mounted...
if [[ "$(grep $dir_dst /proc/mounts)" = "" ]] ; then
# Try to mount the directory.
mount $dir_dst
# Send a message to console or syslog.
if [[ $? -ne 0 ]] ; then
notify("$0 failed to mount $dir_dst")
exit 1;
fi
fi
# Create a backup directory if it does not exist
if [[ -d $dir_dst ]] ; then
mkdir -p $dir_dst 2>/dev/null
fi
# A one-way sync to dir_dst, deleting files that no longer exist in DIR_SRC...
rsync -a --delete $dir_src $dir_dst &> /dev/null
# Check the return status of last command...
if [ $? -eq 0 ]; then
notify("$0: the rsync process succeeded.");
else
notify("$0: the rsync process failed.");
fi
unset dir_src
unset dir_dst
unset b_interactive
答案4
mkdir /office
mount /dev/xvdf /office
mkdir /home
mount /dev/xvdf1 /home
rsync -aHAXxSP /office /home