快速实现功能类似 WinSCP 的同步工具.
inotifywait
命令监控目录的变化;rsync
实现增量同步;inotifywait
是监控涉及文件的操作的事件的, 我们利用此命令监控需要同步的目录,
有增/删/改等操作时, 命令就返回.
rsync
基本用法见其 man 文档, 本处使用的是 rsync [OPTION...] SRC... [USER@]HOST:DEST
.
inotifywait
与 rsync
工具, 且接收方有 ssh 服务器 的应该都行, 但未测试)rsync
在同步时不用密码, 需要设置无密码 ssh
登录.test -e ~/.ssh/id_rsa.pub || ssh-keygen
命令说明:
ssh-keygen
命令即可, 但有些系统可能已经创建过 pub key, 故命令先测试需要的文件是否存在.# ssh-copy-id <远程服务器登录账号>@<远程地址>, 如:
ssh-copy-id root@10.0.2.2
此处需输入远程服务器上, 对应 <远程服务器登录账号> 的登录密码.
监听当前目录下的 project
目录, 目标为到 root@localhost:~/ 下
#!/bin/bash
# sync_project.sh file
# chen-qx@live.cn
ret_code=0
do
if [[ $ret_code -eq 0 ]]; then
rsync -e ‘ssh -p 20052‘ -lurpEAXogDth --progress project root@localhost:~/
else
echo "invalid code return from inotifywait $?" >&2
fi
inotifywait -r -e modify -e create -e delete -e move project
ret_code=$?
sleep 1
done
script 使用的命令说明:
inotifywait
的
-r
选项是监控目录之内所有内容(包括文件及子目录),-e <event>
是指定文件系统事件, 见参考文档[3]. 如果不确定事件对应哪种操作, 可使用 inotifywait -r -m /path/to/foo/
命令监控 foo
目录, 再进行些文件操作, 如创建,删除等, 以查看产生的事件名称. 示例中列出事件应该是全了.rsync
的 ‘ssh -p 20052‘
是指定端口的选项. (本处是从物理机同步到虚拟机中)rsync
增加 --delete
选项. 因多数是同步源码使用, 加此选项的风险用户自负..xxx.swp
文件, 此时用 rsync
的 --exclude ‘.*.swp --exclude ‘.vscode‘ --exclude ‘.git‘‘
来排除. .具体见文档最终更改:
#!/bin/bash
# file: sync_project.sh
# chen-qx@live.cn
function usage() {
cat <<EOF
usage:
$0 [-p port] src1 [ src2 src2 ...] dest
EOF
}
declare -a USER_PATHS
SSH_PORT=""
MAYBE_DST=""
while true
do
case $1 in
"-h" | "--help")
usage
exit 0
;;
"-p" | "--port")
shift 1
p=$1
shift 1
tmp_p=$(echo -n $p | sed -r -e ‘s@^\s*([0-9]+).*@\1@g‘)
if [[ -n "$tmp_p" && "$tmp_p" != "$p" ]]; then
echo "invalid port: $p" >&2
usage >&2
exit 1
fi
SSH_PORT=$tmp_p
;;
*)
if [[ -z "$1" ]]; then
if [[ -n "$MAYBE_DST" ]]; then
USER_PATHS[${#USER_PATHS[@]}]="$MAYBE_DST"
fi
break
fi
tmp_path="$1"
shift 1
# 应对端口指定在命令末尾的情形
if [[ -n "$MAYBE_DST" ]]; then
echo "invalid source path: $MAYBE_DST" >&2
exit 1
fi
if [[ ! -e "$tmp_path" ]]; then
MAYBE_DST="$tmp_path"
## echo $MAYBE_DST
continue
fi
# duplicate
u_real_path=$(realpath "$tmp_path")
for ((i=0;i<${#USER_PATHS[@]}; i++))
do
real_path=$(realpath "${USER_PATHS[$i]}")
if [[ "$real_path" == "$u_real_path" ]]; then
echo "duplicated path: $tmp_path" >&2
exit 1
fi
done
if [[ "$u_real_path" != "/" ]]; then
# echo "tmp_path: -- $tmp_path"
# rsync 有个特性, 如果源目录以 ‘/‘ 结尾, 则目录本身不会同步, 只同步目录下的内容,
# 如有目录结构 a/file1, 则参数写成 a/ 时, 直接将 file1 同步出去, 而 a 目录在目标
# 上并不会被建立.
# 所以, 此处要将路径末尾的 ‘/‘ 去掉
tmp_path=$(echo -n "$tmp_path" | sed -r -e ‘s@(.*[^/])/*$@\1@g‘)
fi
USER_PATHS[${#USER_PATHS[@]}]="$tmp_path"
;;
esac
done
PATH_COUNT=${#USER_PATHS[@]}
if [[ $PATH_COUNT -lt 2 ]]; then
echo "invalid path" >&2
usage >&2
exit 1
fi
DST_IDX=$(expr $PATH_COUNT - 1 )
DST_PATH="${USER_PATHS[DST_IDX]}"
cat <<EOF
source path: ${USER_PATHS[@]:0:$DST_IDX}
destination path: $DST_PATH
EOF
if [[ -n "$SSH_PORT" ]]; then
cat <<EOF
ssh port: $SSH_PORT
EOF
fi
if [[ -z "$SSH_PORT" ]]; then
SSH_PORT=22
fi
ret_code=0
while true
do
if [[ $ret_code -eq 0 ]]; then
### 将删除操作也同步有一定危险性,确实需要的话,将下行加到 rsync 选项中去
### --delete rsync -e "ssh -p $SSH_PORT" -lurpEAXogDth --progress --exclude ‘.*.swp‘ --exclude ‘.vscode‘ --exclude ‘.git‘ ${USER_PATHS[@]}
# ${SRC_PATH[@]} "$DST_PATH"
else
echo "invalid code return from inotifywait $?" >&2
fi
inotifywait -r -e modify -e create -e move_self -e delete -e move ${USER_PATHS[@]:0:$DST_IDX}
echo ‘hello‘
ret_code=$?
sleep 1
done
注意
move_self
事件, 从字面上着实理解不了, 但最终例子中还是加了 -e move_self
rsync
指定端口 https://stackoverflow.com/questions/4549945/is-it-possible-to-specify-a-different-ssh-port-when-using-rsyncrsync
命令手册 man:rsync(1)
inotifywait
手册 man:inotifywait(1)
原文:https://www.cnblogs.com/tseesing/p/15135174.html