这个使用过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")))
可以.貌似可以用.
感谢分享!考虑一下扩展成 melpa package?
没弄过melpa,等有时间折腾折腾
能不能改成,去掉这个前提条件:"这个只是在远端和本地的相同文件夹下进行操作".
其实我这里原始函数默认是当前文件夹,而当按键前加C-u时,可以选择不同文件夹。这时候,调用另外一个counsel-read-file-for-rsync函数,通过tramp选择文件和位置,但我对tramp感觉不太好,不怎么用,就没贴出来。有兴趣的话,可以看一下。
还有,这里面还有在终端下面,用percol来做界面的rsync的函数,widget-percol-rsync-pull和widget-percol-rsync-push,我觉得也挺好用。
你好, 我在使用你的代码时出现了错误:
Debugger entered--Lisp error: (wrong-type-argument consp nil)
setcdr(nil ("Rsync/Unison push "))
(progn (setcdr (symbol-value --cl-pos--) (cons (concat "Rsync/Unison " (symbol-value --cl-mode-string--) " ") (cdr (symbol-value --cl-pos--)))) (set-process-sentinel process (list (quote lambda) (quote (&rest --cl-rest--)) (list (quote apply) (list (quote function) (function (lambda (G3 G4 process signal) (if ... ...)))) (list (quote quote) --cl-mode-string--) (list (quote quote) --cl-pos--) (quote --cl-rest--)))))
(let ((--cl-pos-- (make-symbol "--pos--")) (--cl-mode-string-- (make-symbol "--mode-string--"))) (setf (symbol-value --cl-pos--) (memq (quote mode-line-modes) mode-line-format) (symbol-value --cl-mode-string--) action) (progn (setcdr (symbol-value --cl-pos--) (cons (concat "Rsync/Unison " (symbol-value --cl-mode-string--) " ") (cdr (symbol-value --cl-pos--)))) (set-process-sentinel process (list (quote lambda) (quote (&rest --cl-rest--)) (list (quote apply) (list (quote function) (function (lambda ... ...))) (list (quote quote) --cl-mode-string--) (list (quote quote) --cl-pos--) (quote --cl-rest--))))))
(lexical-let ((pos (memq (quote mode-line-modes) mode-line-format)) (mode-string action)) (setcdr pos (cons (concat "Rsync/Unison " mode-string " ") (cdr pos))) (set-process-sentinel process (function (lambda (process signal) (if (memq (process-status process) (quote (exit signal))) (progn (message "Rsync/Unison %s done." mode-string) (setcdr pos (remove ... ...))))))))
(let ((process (start-process-shell-command "rsync" "*rsync*" rsync-command))) (lexical-let ((pos (memq (quote mode-line-modes) mode-line-format)) (mode-string action)) (setcdr pos (cons (concat "Rsync/Unison " mode-string " ") (cdr pos))) (set-process-sentinel process (function (lambda (process signal) (if (memq (process-status process) (quote ...)) (progn (message "Rsync/Unison %s done." mode-string) (setcdr pos ...))))))))
(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) (let* ((--cl-escape-local-- (function (lambda (x) (replace-regexp-in-string string-to-escape "\\\\\\1" x)))) (--cl-escape-remote-- (function (lambda (x) (replace-regexp-in-string string-to-escape "\\\\\\\\\\\\\\1" x))))) (progn (let ((files (cond (is-push ...) (is-pull ...))) (dest (cond (is-pull ...) (is-push ...)))) (setq rsync-command "rsync -arv --progress ") (let ((--dolist-tail-- files) file) (while --dolist-tail-- (setq file (car --dolist-tail--)) (setq rsync-command (concat rsync-command file " ")) (setq --dolist-tail-- (cdr --dolist-tail--)))) (setq rsync-command (concat rsync-command dest))))) (let ((process (start-process-shell-command "rsync" "*rsync*" rsync-command))) (lexical-let ((pos (memq (quote mode-line-modes) mode-line-format)) (mode-string action)) (setcdr pos (cons (concat "Rsync/Unison " mode-string " ") (cdr pos))) (set-process-sentinel process (function (lambda (process signal) (if (memq ... ...) (progn ... ...))))))))
swint-dired-rsync("push")
(lambda (&optional arg) (interactive "P") (swint-dired-rsync "push"))(nil)
funcall-interactively((lambda (&optional arg) (interactive "P") (swint-dired-rsync "push")) nil)
call-interactively((lambda (&optional arg) (interactive "P") (swint-dired-rsync "push")) nil nil)
command-execute((lambda (&optional arg) (interactive "P") (swint-dired-rsync "push")))
好像是:
(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)))))))
中 pos
这个变量在我电脑中获取到为 nil
, 我不知道这个参数的作用, 能够帮忙解释下?
这里是执行命令的时候在mode-line上加一个提示,把pos相关的行都去掉不影响使用。出错可能是你的mode-line上面本身不显示major mode和minor mode这些的提示符,mode-line-format里面没有mode-line-modes这个东西。无所谓的,把有pos的行去掉就行勒。
最近发现total commander里面安装sftp插件,就可以通过ssh打开远程电脑上文件夹,像手机上本地文件夹一样,应该只要支持sftp的文件管理器都可以。
感觉比傻傻的按手机上的小键盘好多了,小手机总容易按错。
打开eshell,然后命令行rsync或sftp
如果只是编辑服务器端的文件,可以tramp直接编辑