我有以下脚本用于rsync
备份和同步我的文件。
如何使这个脚本更紧凑、更快并且具有更好的错误处理能力?
#!/bin/sh
errors=""
sudo rsync -avh --delete --no-o --no-g /home/xralf/audio /media/extdevice/rsync_backups/
if [ "$?" -eq "0" ]
then
echo "no errors in audio"
else
errors="${errors}error in audio\n"
fi
sudo rsync -avh --delete --no-o --no-g /home/xralf/books /media/extdevice/rsync_backups/
if [ "$?" -eq "0" ]
then
echo "no errors in books"
else
errors="${errors}error in books\n"
fi
sudo rsync -avh --delete --no-o --no-g /home/xralf/source_code /media/extdevice/rsync_backups/
if [ "$?" -eq "0" ]
then
echo "no errors in source_code"
else
errors="${errors}error in source_code\n"
fi
# more such directories with this code pattern
echo ${errors}
后来我打算不看脚本执行,所以我只想看到结果并相信一切顺利。我运行了脚本,但最终,我拥有的唯一信息是error in source_code
,我看不到错误到底是什么(哪个文件导致了它)。
答案1
如果您的首要任务是袖珍的和快速地(即:最小化进程数量,但在这种情况下,您受到磁盘 IO 的限制,而不是受到 cpu 或内存的限制):
#!/bin/bash
sudo rsync -a --delete --no-o --no-g \
/home/xralf/{audio,books,source_code} \
/media/extdevice/rsync_backups/ &&
echo "rsync completed successfully" 1>&2 || echo "rsync ended with errors" 1>&2
删除该-v
选项将使输出的噪音更少,以便您可以专注于显式错误(如果有)。将1>&2
STDOUT 重定向到 STDERR,以便将错误消息发送到预期的位置。如果无人值守运行,以下替代方案可能是比内置更好的选择echo
,但代价是额外的进程:
服务器可以用来
logger
将消息发送到syslog
集中处理。确切的语法取决于服务器配置。用于
date
添加计时信息,脚本的最后一行变为:
date +"[%Y/%m/%d %H:%M:%S] rsync completed successfully" 1>&2 || \
date +"[%Y/%m/%d %H:%M:%S] rsync ended with errors" 1>&2
输出类似的东西[2022/12/05 14:37:27] rsync completed successfully
答案2
如果您不被迫使用sh
但可以使用更复杂的 shell,例如bash
,您可以执行以下操作:
#!/bin/bash
dirs=( "audio" "books" "source_code" );
errors=()
for dir in "${dirs[@]}"; do
sudo rsync \
-avh --delete --no-o --no-g \
/home/xralf/"$dir" \
/media/extdevice/rsync_backups/ &&
echo "no errors in $dir" ||
errors+=("error in $dir\n")
done
printf '%s\n' "${errors[@]}"
您可能还想捕获 stderr,但这与您的脚本执行相同的操作。
答案3
该rsync
命令接受参数--log-file=FILE
。备份完成后,您可以检查它是否有错误。
为了提高效率,它还接受--exclude-from=FILE
和--include-from=FILE
。您可以创建包含所有内容的列表的文本文件做和不要希望通过单个rsync
命令而不是多个命令来备份和调用它们。
请参阅man rsync
或在线手册页。
答案4
制作一个名为模块.sh并为其提供以下文本:
#!/usr/bin/env bash
# -A=Archive. Use recursion and preserve almost everything.
# -V=Verbose.
# -H=Preserve hard links.
# -Z=Compress.
# --Delete=
# If node in directory 'from' gets deleted,
# delete it in directory 'to'.
# --No-o=No Owner.
# --No-g=No Group.
# The --No's are partially undoing the Archive option.
sync_dir(){
local from="${1}";
local to="${2}";
rsync \
-avhz \
--delete \
--no-o \
--no-g \
"${from}/" \
"${to}" \
1>/dev/null \
;
# Store the sync success.
local sync_result="${?}";
# The project name is the last directory of the from string.
local project_name=$(grep -oE '[^/]*$' <<<"${from}");
local error="No error in: ${project_name}";
if [ "${sync_result}" -ne "0" ]; then
error="Error in: ${project_name}\n";
fi
printf "${error}\n";
};
然后创建另一个文件并从那里获取模块:
#!/usr/bin/env bash
. ./module.sh;
sync_dir '/home/xralf/audio' '/media/extdevice/rsync_backups/';
# More sync dirs here.
注意不同的 Shebang,这个是 POSIX 兼容的。
我还添加了 Rsync 的 -z 选项。它会在途中压缩数据。