一个老问题,大家如何在emacs中远端和本地互穿文件

这个使用过dired中的复制结合emacs-async异步复制,但是感觉emacs-async有时候并不能复制文件,一直提示在复制,实际没有复制,不知道什么问题.老感觉不robust.也在终端使用过scp上传和下载文件.不知道大家就互相传输文件(包括大文件),有没有在emacs中比较好的解决方案.

TRAMP 打开远程文件,再 M-x copy-file

sftp 或磁力链接,不要老想着事事用 emacs 解决。

对了,弄个 HTTPS 也不错。

emacs-async 文件一大或一多就经常歇菜,没什么卵用…

分享自己用rsync在远端和本地互传文件的东西。之前在命令行里面补全各种文件名,后来实在受不了就弄了这个,发现还挺好用的。本质上就是把emacs当作一个选择界面,从~/.ssh/config里面读取远端host名字并选择。如果是下载的话,ssh上去列出要下载的文件并选择,如果是上传的话,在dired里面mark上要上传的文件就可以了。对了,这个只是在远端和本地的相同文件夹下进行操作。

(defun swint-dired-rsync (action)
  (interactive)
  (let ((remote (completing-read "Remote repo: "
                                 (split-string
                                  (shell-command-to-string
                                   "cat ~/.ssh/config | grep \"^host \" | awk '{print $2}'"))))
        (path (abbreviate-file-name default-directory))
        (is-push (equal action "push"))
        (is-pull (equal action "pull"))
        (string-to-escape "\\( \\|(\\|)\\|\\[\\|\\]\\|{\\|}\\)")
        rsync-command)
    ;; 对于rsync,escape本地路径用\,远程路径用\\\。
    (cl-flet ((escape-local (x)
                            (replace-regexp-in-string string-to-escape
                                                      "\\\\\\1" x))
              (escape-remote (x)
                             (replace-regexp-in-string string-to-escape
                                                       "\\\\\\\\\\\\\\1" x)))
      (let ((files (cond (is-push
                          (cl-loop for f in (dired-get-marked-files)
                                   collect (escape-local f)))
                         (is-pull
                          (let ((remote-files (helm-comp-read "Remote files: "
                                                              (split-string (shell-command-to-string
                                                                             ;; 连接remote列出path下文件绝对路径,并不显示错误信息。
                                                                             (format "ssh %s '(cd %s && ls -A | sed \"s:^:`pwd`/:\") 2>/dev/null'"
                                                                                     remote (escape-local path))) "\n")
                                                              :marked-candidates t
                                                              :buffer (format "*helm rsync %s*" remote))))
                            (cl-loop for f in remote-files
                                     collect (concat remote ":" (escape-remote (if (directory-name-p f)
                                                                                   (directory-file-name f)
                                                                                 f))))))))
            (dest (cond (is-pull (escape-local path))
                        (is-push (escape-remote (concat remote ":" path))))))
        (setq rsync-command "rsync -arv --progress ")
        (dolist (file files)
          (setq rsync-command
                (concat rsync-command file " ")))
        (setq rsync-command (concat rsync-command dest))))
    (let ((process (start-process-shell-command "rsync" "*rsync*" rsync-command)))
      (lexical-let ((pos (memq 'mode-line-modes mode-line-format))
                    (mode-string action))
        (setcdr pos (cons (concat "Rsync/Unison " mode-string " ") (cdr pos)))
        (set-process-sentinel
         process
         (lambda (process signal)
           (when (memq (process-status process) '(exit signal))
             (message "Rsync/Unison %s done." mode-string)
             (setcdr pos (remove (concat "Rsync/Unison " mode-string " ") (cdr pos))))))))))

然后绑定快捷键就可以了,希望有帮助。

(global-set-key (kbd "M-g ,") '(lambda (&optional arg) (interactive "P") (swint-dired-rsync "pull")))
(global-set-key (kbd "M-g .") '(lambda (&optional arg) (interactive "P") (swint-dired-rsync "push")))
3赞

可以.貌似可以用.

感谢分享!考虑一下扩展成 melpa package?

没弄过melpa,等有时间折腾折腾

能不能改成,去掉这个前提条件:"这个只是在远端和本地的相同文件夹下进行操作".

其实我这里原始函数默认是当前文件夹,而当按键前加C-u时,可以选择不同文件夹。这时候,调用另外一个counsel-read-file-for-rsync函数,通过tramp选择文件和位置,但我对tramp感觉不太好,不怎么用,就没贴出来。有兴趣的话,可以看一下。

还有,这里面还有在终端下面,用percol来做界面的rsync的函数,widget-percol-rsync-pull和widget-percol-rsync-push,我觉得也挺好用。