自己寫個 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! 🚀