如何打开多个终端?

时间:2010-10-22 02:46:17

标签: emacs

在Emacs中,我经常发现自己需要在各种源文件之间来回切换到各种终端。但是,我觉得我没有很好的方法来有效地执行此操作,而且只能在Emacs(shelleshell或{中打开一个 shell ,这很笨拙{1}})。

此外,我需要在多个终端和源文件之间进行有效的处理。

我怎样才能做到这一点?

13 个答案:

答案 0 :(得分:17)

您当然可以打开多个交互式shell。尝试输入 C-u M-x shell RET RET

答案 1 :(得分:17)

您可以根据需要随时打开多个终端和外壳。只需使用M-x rename-buffer更改现有*term**shell*缓冲区的名称,下次执行M-x termM-x shell时,就会有一个全新的缓冲区被创造。在M-x shell的情况下,前缀参数将使您被提示输入新shell缓冲区的名称,如offby1所示。

几年前,我有一份工作,我必须定期登录名为“host01.foo.com”,“host02.foo.com”等的各种生产服务器。我写了一个像这样的小功能让它们更容易管理:

(defun ssh-to-host (num)
  (interactive "P")
  (let* ((buffer-name (format "*host%02d*" num))
         (buffer (get-buffer buffer-name)))
    (if buffer
        (switch-to-buffer buffer)
      (term "/bin/bash")
      (term-send-string
       (get-buffer-process (rename-buffer buffer-name))
       (format "ssh host%02d.foo.com\r" num)))))

然后我把这个命令绑定到(比方说) s-h (超级H),让我只需输入 M-5 s-h 。如果我还没有名为*host05*的缓冲区,它将启动一个新的终端仿真器缓冲区,将其重命名为*host05*,然后将我转发到host05.foo.com。如果缓冲区*host05*已经存在,它只会将我切换到它。非常方便!

答案 2 :(得分:15)

尝试使用MultiTerm打开多个shell。

答案 3 :(得分:8)

您可以使用Emacs Lisp Screen来模拟GNU Screen,并提供简单的键绑定以跳转到多个不同的shell之间。

答案 4 :(得分:4)

我使用了很多方法将我的终端生活融入Emacs:

  • elscreen.el是一个节省生命的人,如果你有一个像gdb这样复杂的窗口布局,或者只是变得不知所措,你就会打开一个新的屏幕。在您的情况下,您可以将一个屏幕专用于终端。
  • multi-term.el使管理终端更容易。
  • shell-pop.el,一个快速终端访问的好工具。 shell-pop允许您为打开和关闭特定的shell缓冲区窗口分配一个键,如果您使用了tilda之类的下拉终端,那么知道这是多么的方便:

我的shell-pop配置的示例和示例,我使用密钥C-t弹出eshell

(require 'shell-pop)
(shell-pop-set-internal-mode "eshell")     ; Or "ansi-term" if you prefer
(shell-pop-set-window-height 60)           ; Give shell buffer 60% of window
;; If you use "ansi-term" and want to use C-t
;; (defvar ansi-term-after-hook nil)
;; (add-hook 'ansi-term-after-hook
;;           '(lambda ()
;;              (define-key term-raw-map (kbd "C-t") 'shell-pop)))
;; (defadvice ansi-term (after ansi-term-after-advice (org))
;;  (run-hooks 'ansi-term-after-hook))
;; (ad-activate 'ansi-term)
(global-set-key (kbd "C-t") 'shell-pop)

答案 5 :(得分:3)

我通常做一个 M - x server-start,然后使用emacsclient --no-wait打开文件。我已经将其与e混淆了一些装饰,以便它更方便一些。

我在一个终端中完成所有工作,只需使用e将要编辑的文件“抛出”到Emacs中。在Emacs内部,我使用iswitchb来玩弄它并且它工作得很好。 YMMV。

答案 6 :(得分:3)

我经常在旧工作场所使用10个左右的贝壳。秘诀是你必须重命名其他shell缓冲区。我在我的.emacs中自动完成了这项操作,在逻辑上创建和命名shell(我为每个项目都有projnameRun和projnameBuild)。与任何事物一起工作得非常好,使得重新绑定正确的shell非常容易(使用项目名称的末尾与r或b结合运行/构建)。

答案 7 :(得分:2)

我没有在emacs中使用多个终端窗口,而是在需要新终端时,我会生成不同的xterm。这当然是可以忍受的,因为我使用一个非常轻量级的终端模拟器(urxvt),它的启动时间不到0.2秒。
然后我使用我的窗口管理器在它们和emacs帧之间切换。可配置的窗口管理器将有很多选项可以调整以在窗口之间切换(非常)。在emacs中,我使用windmove和ido-mode,并且已经将C-tab绑定到切换到最后一个缓冲区的函数(因为我以这种方式使用C-x b)。

嗯,不确定它对你有多大用处,因为它与你的使用模式完全不同,但这对我有用。

答案 8 :(得分:2)

几年前我遇到了完全相同的问题,并没有发现让我感到满意的事情;所以我写了自己的“toggle shell”功能。它在当前帧或窗口配置与系统shell缓冲区之间切换。它还可以将shell放入专用框架,并将pushd注入当前缓冲区目录。

这是摘自my .emacs

(defvar --toggle-shell-last-window-conf nil "The last window configuration.")
(defvar --toggle-shell-last-buf nil "The last buffer object in case there's no last window configuration.")
(defvar --toggle-shell-last-frame nil "The frame that was selected when opening a shell buffer.")

(defun --toggle-shell-have-conf ()
  (window-configuration-p --toggle-shell-last-window-conf))

(defun --toggle-shell-store-last-conf ()
  (setq --toggle-shell-last-buf (current-buffer)
    --toggle-shell-last-frame (selected-frame)
    --toggle-shell-last-window-conf (current-window-configuration)))

(defun --toggle-shell-restore-last-conf ()
  (if (--toggle-shell-have-conf)
      (progn (raise-frame --toggle-shell-last-frame)
         (set-window-configuration --toggle-shell-last-window-conf))
    (let ((bufnam (if (bufferp --toggle-shell-last-buf)
              (buffer-name --toggle-shell-last-buf) --toggle-shell-last-buf)))
      (if bufnam
      (if (get-buffer bufnam) (switch-to-buffer bufnam t)
        (message "%s: buffer not available" bufnam))))))

(defun --toggle-shell (&optional display inject-cd)
  "Toggles between current buffers and a system shell buffer. With prefix-arg
close the shell.

When DISPLAY is 'vertical splits the shell as vertical window; when 'frame uses
a dedicated frame (default: single window). When INJECT-CD executes a `pushd'
to the working directory of the buffer from which you toggled the shell."
  (interactive)
  (let* ((shell-buf (get-buffer "*shell*"))
     (shell-window          ; non-nil when currently displayed
      (if shell-buf (get-buffer-window shell-buf t)))
     (shell-frame
      (if shell-window (window-frame shell-window)))
     (in-shell (eq (current-buffer) shell-buf))
     (vertical (string= display 'vertical))
     (popup-frame (or (string= display 'frame)
              (and inject-cd (not (bufferp shell-buf)))
              (and (framep shell-frame)
                   (not (eq shell-frame (selected-frame)))))))
    ;; With prefix-arg close shell, restore windows. Otherwise (no prefix-arg)
    ;; toggle shell window; restore windows when called twice in a row, or the
    ;; current buffer is the shell buffer (`in-shell').
    (if current-prefix-arg
    (if (bufferp shell-buf)
        (progn (message "Exiting shell '%s'" (buffer-name shell-buf))
           (kill-buffer shell-buf)
           (if in-shell (--toggle-shell-restore-last-conf)))
      (error "No shell buffer to kill."))
      ;; If already in shell-buffer toggle back to stored frame-configuration.
      (if (and in-shell (not inject-cd))
      (progn
        (--toggle-shell-restore-last-conf)
        ;; Recurse to reopen the shell-buffer in a dedicated frame, or
        ;; close the dedicated frame and reopen the buffer in a window.
        (if (and popup-frame (eq shell-frame (selected-frame)))
        (--toggle-shell 'frame inject-cd)
          (when (and popup-frame shell-frame)
        (delete-frame shell-frame)
        (--toggle-shell nil inject-cd))))
    ;; Not in shell buffer. Warp to it or create new one.
    (unless in-shell
      (--toggle-shell-store-last-conf))
    (if popup-frame
        (progn (switch-to-buffer-other-frame (or shell-buf "*shell*"))
           (raise-frame
            (or shell-frame (window-frame (get-buffer-window "*shell*" t)))))
      (if (> (count-windows) 1)
          (delete-other-windows)))
    ;; Finally `cd' into the working directory the current buffer.
    (let ((new-shell (not (bufferp shell-buf)))
          (new-dir       ; `default-directory' of `--toggle-shell-last-buf'
           (if --toggle-shell-last-buf
           (buffer-local-value 'default-directory --toggle-shell-last-buf))))
      ;; Open shell, move point to end-of-buffer. The new shell-buffer's
      ;; `default-directory' will be that of the buffer the shell was
      ;; launched from.
      (when vertical
        (if (> (count-windows) 1)
        (delete-other-windows))
        (split-window-vertically) (other-window 1))
      (funcall 'shell)
      (when new-shell
        (message "New shell %s (%s)" (buffer-name (current-buffer)) new-dir)
        (if inject-cd (sit-for 2))) ; wait for prompt
      (goto-char (point-max))
      ;; If on a command-prompt insert and launch a "cd" command (assume no
      ;; job is running).
      (when (and inject-cd new-dir)
        (save-excursion
          (backward-line-nomark) (end-of-line)
          (unless (setq inject-cd (re-search-forward comint-prompt-regexp (point-max) t))
        (error "Cannot `pushd', shell is busy")))
        (when (and inject-cd)
          (let* ((cmd (format
               "pushd '%s' %s" (comint-quote-filename new-dir)
               (if (buffer-file-name --toggle-shell-last-buf)
                   (format "# '%s'" (file-name-directory (buffer-file-name --toggle-shell-last-buf)))
                 ""))))
        ;; `shell-process-cd' set new `default-directory' and set
        ;; `shell-last-dir' to old. (If the pushd command is
        ;; successful, a dirs is performed as well; >nul discards this
        ;; output.)
        (shell-process-cd new-dir)
        (insert cmd)
        (comint-send-input)
        (message "%s: cd '%s'" (buffer-name --toggle-shell-last-buf) new-dir))
          )
        )
      )
    )
      )
    )
  )

--toggle-shell是完成这一伎俩的功能。我把它绑定到F12:

;;  F12         toggle between shell buffer and current window configuration
;;  SHIFT-F12 like before, but let shell buffer appear in a dedicated frame
;;  ALT-F12     inject a pushd to change to directory of current buffer
;;  CTRL-F12  `shell-command'

(global-set-key [(f12)] '--toggle-shell)
(global-set-key [(shift f12)] '(lambda()(interactive)(--toggle-shell 'frame)))
(global-set-key [(meta f12)] '(lambda()(interactive)(--toggle-shell nil t)))
(global-set-key [(meta f10)] '(lambda()(interactive)(--toggle-shell nil t)))
(global-set-key [(control f12)] 'shell-command) ; alias M-!

这是一大堆代码,可以在这里发布。但它应该运作良好。

答案 9 :(得分:2)

半相关 - 您可以使用

在所选文件上快速运行shell命令
M-shift-!

它为较小的命令chmod等节省了大量时间

答案 10 :(得分:1)

也许我的快速弹出式shell也可以帮到你。 A quick pop-up shell for emacs

答案 11 :(得分:0)

Ecb + eshell将是你想要的!

答案 12 :(得分:0)

我使用vi,但希望这会有所帮助。我可以打开尽可能多的终端(例如在Ubuntu 16.04中):

  ctrl + alt + t

我通常打开2个终端,并通过以下方式将一个终端移动(定位)到:

  ctrl + super + right-arrow

并通过以下方式将另一个终端移到左侧:

  ctrl + super + left-arrow

所以我有2个终端的分屏。