2017年 7月 8日

dired で rsync する

Emacs

タイトル通り dired で rsync しようということです。ここしばらく使っていますがそこそこ便利なものです。

(defvar *dired-rsync-default-option* "-auv")

(defun dired-rsync-directory-name (dir)
  (if (string-match "^/[^:]+:\\(.+\\)$" dir)
       (match-string-no-properties 1 dir)
     dir))

(defun dired-do-rsync ()
  (interactive)
  (let* ((dired-dwim-target t)
         (target (dired-rsync-directory-name
                  (expand-file-name
                   (read-file-name "rsync to: " (dired-dwim-target-directory)))))
         (options (read-from-minibuffer "options: " *dired-rsync-default-option*))
         (dir (dired-rsync-directory-name (expand-file-name (dired-current-directory))))
         (files (mapcar 'file-name-nondirectory (dired-get-marked-files)))
         (win (selected-window))
         (buf (pop-to-buffer "*rsync*")))
    (erase-buffer)
    (dolist (f files)
      (start-process-shell-command
       "dired-rsync"
       buf
       (format "rsync %s %s%s %s" options dir (shell-quote-argument f) target))
      (newline))
    (select-window win)))

途中で強制終了ができないので注意してください。メジャーモードとしてしっかり書けばいいのですがそれは面倒なので手抜きです。

もう一つ注意点としては dired でマークしたディレクトリには末尾にスラッシュがつかないという点があります。つまり dir/ ではなく dir として扱われるということです。これは rsync では重要なので強調しておきます。--delete オプションをつけるときには特に注意して下さい。痛い思いをすることがあります。

デフォルトのオプション *dired-rsync-default-option*-auv にしてありますが、自分の良く使うものに変更すると良いでしょう。

dired-rsync-directory-name は tramp のリモートディレクトリを /ssh:ryo1@hostname:path/to/dir としたとき /ssh: の部分を無視するための関数です。正規表現はあまり自信はないのでもし問題があれば修正してください。

dired-do-rsync の最初の (dired-dwim-target t) は不要かもしれません。あっても損ではないのでそのままにしてあります。

キーバインドは好みの問題ですが

(define-key dired-mode-map (kbd "C-c r") 'dired-do-rsync)

普通の dired のコマンドのように一文字でもいいと思います。