自己写个 rsync
+ fswatch
实时增量同步脚本,干掉 Cursor AI、Sublime Text 的 SFTP等 插件!
作为一个码农,我最头疼的事情之一就是编辑器同步代码到服务器这块。用过各种各样的sftp、rsync插件,感觉不好用。。
我琢磨着:难道就没有既快速,又安全,还能只上传修改过文件差异的解决方案?最终,我自己动手写了个基于 rsync
+ fswatch
的实时增量同步脚本,实现了只同步新增和修改文件,不做全量同步,支持任何编辑器,简单又靠谱。
说说这几个插件的坑
- Cursor AI 的 SFTP:传输速度慢得哭,尤其项目文件多一点,等得我花儿都谢了。
- Sublime Text 的 SFTP:要收费,虽说速度能快点,但不支持 rsync,上传的是整个文件,没法只传差异处,浪费流量和时间。
我的解决思路
为什么不自己写个脚本,用 rsync 来同步,只针对新增和修改的文件?而且还不被编辑器限制?
- 只上传改动的文件,大大节省时间和带宽
- 用
fswatch
实时监听文件变化,做到自动触发同步 - 支持配置排除目录,避免上传
.git
、node_modules
等垃圾文件夹 - 彩色输出日志,清晰明了,方便调试
- 同步成功还能播放提示音,避免盯屏幕发呆
- 任何编辑器都能用,不依赖插件,灵活又安全
环境准备
- macOS/Linux,本文以 macOS 为例
- 安装
fswatch
:
brew install fswatch
- 安装
jq
:
brew install jq
- 配置好 SSH 免密登录服务器
配置文件示例(rsync_config.json
)
{"remote_host": "11.22.33.44","remote_user": "root","remote_path": "/www/wwwroot/test.myprojec.com","exclude": [".git", "node_modules", "dist"]
}
核心脚本:rsync_project.sh
#!/bin/bashRED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
RESET='\033[0m'# 获取脚本路径
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TIMESTAMP=$(date +%s)
LOG_FILE="$SCRIPT_DIR/.rsync_sync_${TIMESTAMP}.log"if [[ -z "$1" ]]; thenecho -e "${RED}[错误] 请输入项目根目录路径,比如:sh rsync_project.sh ~/my-project${RESET}"exit 1
fiPROJECT_DIR="$(cd "$1" && pwd)"
CONFIG_FILE="$PROJECT_DIR/rsync_config.json"
DETAILED=falsefor arg in "$@"; doif [[ "$arg" == "--detail" ]]; thenDETAILED=truefi
doneif [[ ! -f "$CONFIG_FILE" ]]; thenecho -e "${RED}[错误] 找不到配置文件:$CONFIG_FILE${RESET}"exit 1
fiif ! command -v jq &> /dev/null; thenecho -e "${RED}[错误] 你需要先装 jq:brew install jq${RESET}"exit 1
fiif ! command -v fswatch &> /dev/null; thenecho -e "${RED}[错误] 你需要先装 fswatch:brew install fswatch${RESET}"exit 1
fiREMOTE_HOST=$(jq -r '.remote_host' "$CONFIG_FILE")
REMOTE_USER=$(jq -r '.remote_user' "$CONFIG_FILE")
REMOTE_PATH=$(jq -r '.remote_path' "$CONFIG_FILE")EXCLUDE_ARR=()
for line in $(jq -r '.exclude[]?' "$CONFIG_FILE"); doEXCLUDE_ARR+=("${line%/}")
doneif [[ -z "$REMOTE_HOST" || -z "$REMOTE_USER" || -z "$REMOTE_PATH" ]]; thenecho -e "${RED}[错误] 配置文件缺少 remote_host、remote_user 或 remote_path${RESET}"exit 1
fiecho -e "${BLUE}[测试] 尝试连接 $REMOTE_USER@$REMOTE_HOST ...${RESET}"
ssh -q -o ConnectTimeout=5 "$REMOTE_USER@$REMOTE_HOST" "echo pong" 2>/dev/null
if [[ $? -ne 0 ]]; thenecho -e "${RED}[失败] 无法连接服务器 $REMOTE_USER@$REMOTE_HOST,请检查 SSH 配置${RESET}"exit 1
fiecho -e "${GREEN}[√] 成功连接服务器:$REMOTE_USER@$REMOTE_HOST${RESET}"
echo -e "${CYAN}目标路径:$REMOTE_PATH${RESET}"
$DETAILED && echo -e "${YELLOW}[模式] 详细日志已启用${RESET}"
echo -e "${BLUE}[日志] 同步记录保存到:$LOG_FILE${RESET}"HAS_OSASCRIPT=false
command -v osascript &> /dev/null && HAS_OSASCRIPT=trueecho -e "${BLUE}[监听中] 等待文件变更...${RESET}"fswatch -0 -e "\\.DS_Store$" "$PROJECT_DIR" | while IFS= read -r -d "" changed_path; doskip=falsefor excl in "${EXCLUDE_ARR[@]}"; do[[ "$changed_path" == *"/$excl/"* || "$changed_path" == *"/$excl"* ]] && skip=true && breakdone$skip && continue[[ ! -f "$changed_path" ]] && continueREL_PATH="${changed_path#"$PROJECT_DIR"/}"CURRENT_TIME=$(date '+%Y-%m-%d %H:%M:%S')echo ""echo -e "${BLUE}[变更] 文件新增或修改:$REL_PATH${RESET}"echo -e "${MAGENTA}[时间] $CURRENT_TIME${RESET}"RSYNC_CMD=(rsync -az -e "ssh")RSYNC_CMD+=(--rsync-path="mkdir -p \"$(dirname "$REMOTE_PATH/$REL_PATH")\" && rsync")RSYNC_CMD+=("$changed_path" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/$REL_PATH")if $DETAILED; thenecho -e "${CYAN}[执行] rsync 命令:${RESET}"printf '%q ' "${RSYNC_CMD[@]}"echo ""elseecho -e "${CYAN}[执行] 正在同步文件...${RESET}"fiecho "[$CURRENT_TIME] 变更文件: $REL_PATH" >> "$LOG_FILE""${RSYNC_CMD[@]}" >> "$LOG_FILE" 2>&1if [[ $? -eq 0 ]]; then# 同步成功后设置 chownssh "$REMOTE_USER@$REMOTE_HOST" "chown www:www \"$REMOTE_PATH/$REL_PATH\"" >> "$LOG_FILE" 2>&1echo -e "${GREEN}[完成] 同步成功 ✅ 并设置权限为 www:www${RESET}"echo "[$CURRENT_TIME] ✅ 同步成功并设为 www" >> "$LOG_FILE"if command -v afplay &> /dev/null; thenafplay /System/Library/Sounds/Tink.aiff &fi$HAS_OSASCRIPT && osascript -e 'display notification "文件同步成功" with title "rsync" sound name "Glass"'elseecho -e "${RED}[失败] 同步失败 ❌${RESET}"echo "[$CURRENT_TIME] ❌ 同步失败" >> "$LOG_FILE"$HAS_OSASCRIPT && osascript -e 'display notification "文件同步失败" with title "rsync" sound name "Basso"'fi
done
使用方法
bash rsync_project.sh myprojec --detail
替换 myprojec
为你的项目目录,--detail
参数可选,开启详细日志。
结语
用这套脚本后,文件改动几乎立刻上传,速度杠杠的,且不乱上传无用文件,安全又高效。再也不用担心编辑器 SFTP 插件各种坑,支持所有编辑器,只要能保存文件,统统适用。
如果你也被那些插件折磨过,不妨试试我这套 rsync + fswatch
脚本,真心好用!
欢迎大家留言交流,遇到问题咱们一起吐槽、优化!
Happy coding! 🚀