Remote ssh connection from within Emacs - emacs

Several questions, including this one, discuss aspects relating to ssh connections from within Emacs. I haven't found an answer to my question though: How can I ssh into a remote machine from within Emacs?
I do not wish to edit a file on the remote machine from within Emacs. I am aware of M-x shell which opens a shell on my local machine and I am aware of using TRAMP to edit a file over ssh on the remote machine. However, neither of these relate to this question.
(Instead of voting to close, maybe migrate the question to another site.)
Edit: Related discussion here.

Firstly, I am unaware of a native elisp ssh client (and do not imagine there is a great deal of motivation for writing one), so you will certainly need to interact with an external ssh client process.
As you wish to use ssh interactively, the ssh process requires a terminal on the local side of the connection.
The question therefore becomes: Does Emacs implement a terminal to which an ssh process can be attached?
The answer is: yes -- term.el provides a robust terminal implementation, through which ssh can be run directly, without the requirement for a shell.
If you run M-x term RET you will be prompted for a program. (It defaults to a shell, but that is certainly not the only type of process you can run.)
For reasons unknown, the interactive term (and ansi-term) functions do not support passing arguments to the specified program, which renders them less useful if you wished to run something like ssh user#host. You could instead specify a script which handled the arguments, but we can manage that in elisp as well:
The term function is actually a simple wrapper which calls make-term to start the program and then sets the appropriate modes. As make-term does accept program arguments, it is quite straightforward to copy-and-modify the definition of term to suit your own purposes.
Here is a very simple implementation:
(defun my-ssh (user host port)
"Connect to a remote host by SSH."
(interactive "sUser: \nsHost: \nsPort (default 22): ")
(let* ((port (if (equal port "") "22" port))
(switches (list host "-l" user "-p" port)))
(set-buffer (apply 'make-term "ssh" "ssh" nil switches))
(term-mode)
(term-char-mode)
(switch-to-buffer "*ssh*")))
or perhaps this is preferable:
(defun my-ssh (args)
"Connect to a remote host by SSH."
(interactive "sssh ")
(let ((switches (split-string-and-unquote args)))
(set-buffer (apply 'make-term "ssh" "ssh" nil switches))
(term-mode)
(term-char-mode)
(switch-to-buffer "*ssh*")))
Obviously there is scope for improvements, but I think that's fairly useful as-is.
You should ensure that you are familiar with the quirks of term-mode. See:
M-: (info "(emacs) Terminal emulator") RET
M-: (info "(emacs) Terminal Mode") RET
C-hf term-mode RET

It turns out, there is what you want:
(setq rlogin-program "ssh")
(setq rlogin-process-connection-type t)
and then M-x rlogin RET <myhost> RET will do that.

Maybe ssh.el is what you are looking for. The ssh command provides a single-step way to create remote shells in Emacs via ssh, including specifying the user name in a natural way, and enabling tramp directory tracking if desired.

I'm not sure I understand. Open up M-x ansi-term and run ssh user#host there?

Related

Locate and open remote files

In emacs, the locate command provides a way to run unix's locate and open files on the local filesystem.
I'm using TRAMP to access remote files - is it possible to use emacs' locate to find and open remote files?
Likely, it is not possible. locate uses call-process, which does not run remote processes.
I don't know if you can use Emacs's locate function with TRAMP per se, but you could connect to a host remotely and run locate on that system via M-x shell or M-x eshell. I have some wrapper functions which make this task easier (although I mostly got them from elsewhere):
(defun remote-eshell (host)
(interactive "sHost: ")
(let ((default-directory (concat "/ssh:" (format "%s:" host))))
(eshell host)))
(defun remote-shell (host)
(interactive "sHost: ")
(let ((default-directory (concat "/ssh:" (format "%s:" host))))
(shell)))
After locating the desired files on the remote host, you can then open them via TRAMP using C-x C-f /ssh:remotehost
Also, if you're connecting via TRAMP to a remote host, you should make sure that said host is not sending any weird prompts since TRAMP doesn't handle those well. See more about that here.

eshell TRAMP find remote file with relative path (or at least less than the full Tramp path)?

I love eshell's TRAMP integration. With it I can do cd /ssh:foo:/etc to
ssh into a remote machine and visit its /etc/ directory. I can also do
find-file motd to open this file in my local emacs. However, what if I need to use sudo to change the file? I know I can give the
full path, like so:
find-file /sudo:foo:/etc/motd
but is there a way to open the file via TRAMPs sudo support, without having to type the full path?
I managed to came up with the following eshell alias that works for me:
alias sff 'find-file "${pwd}/$1"(:s/ssh/sudo/)'
It should be fairly obvious what it does. It prepends the working directory
path, but with the string ssh replaced by sudo. Thus it only works for
remote files accessed over ssh. I rarely edit files using sudo locally, so
that's not a problem for me. However, we can make it work for local files too, at the cost of complexity:
alias sff 'find-file "${pwd}/$1"(:s,^,/sudo::,:s,::/ssh:,:,)'
That is, prepend /sudo:: (which is how to sudo for local files) and
subsequently replace any ocurrence of ::/ssh: with :. (I would have just removed :/ssh:, but eshell's :s/// construct didn't accept an empty
replacement.)
I found an alternative answer that works very well over at EmacsWiki.
Using that you'd still open the file with find-file as usual, but then
invoke M-x sudo-edit-current-file (shown below) to re-open the file as root
using Tramp. I think this is a very elegant solution, because often I
initially just want to look at a file, then later find that I need to edit it.
Here's the function, in case it disappears from the page above:
(set-default 'tramp-default-proxies-alist (quote ((".*" "\\`root\\'" "/ssh:%h:"))))
(require 'tramp)
(defun sudo-edit-current-file ()
(interactive)
(let ((position (point)))
(find-alternate-file
(if (file-remote-p (buffer-file-name))
(let ((vec (tramp-dissect-file-name (buffer-file-name))))
(tramp-make-tramp-file-name
"sudo"
(tramp-file-name-user vec)
(tramp-file-name-host vec)
(tramp-file-name-localname vec)))
(concat "/sudo:root#localhost:" (buffer-file-name))))
(goto-char position)))

I want to run the cygwin bash shell from native windows emacs app

I have followed instructions from How can I run Cygwin Bash Shell from within Emacs? this question and I have gone further and added the (setq explicit-bash-args '("--login" "-i")) command, however emacs continues to only display the dos prompt when I type M-x shell. In summery my .emacs file looks like this:
(defun cygwin-shell ()
"Run cygwin bash in shell mode."
(interactive)
(let ((explicit-shell-file-name "C:/cygwin/bin/bash"))
(call-interactively 'shell)))
(setq explicit-bash-args '("--login" "-i"))`
Please be gentle with the answers as I am right at the bottom of the famous vertical emacs learning curve!
If you implemented the answer from that question, note that you have to do M-x cygwin-shell to start bash. If you want to use it for every M-x shell you need to call
(setq explicit-shell-file-name "C:/cygwin/bin/bash")
Since you stated that you are learning, here's a few tips when trying this out.
type C-x C-f ~/.emacs to open your .emacs file in your user path.
Enter your function above at the end
M-x load-file [RET] .emacs: loads the buffer (no need to restart emacs)
C-h a: If you are interested in some specific action, you can look it up
C-h v [RET] variable: can inspect the variable, check the value of explicit-bash-args for instance
And, btw, I'm not sure what the "--login -i" does, but someone stated in a comment that you should have that so "ls" would work. If you have your cygwin bin path in your PATH environment variable, bash will find ls anyway. No need to escape the path variable either, this is handled by bash (do an echo $PATH in bash when you get it working and you'll see).

How to run multiple shells on Emacs

I am using Emacs 23.3.1 on windows 7. I know that I can run shell from emacs using M-x shell. I would like to have multiple shell windows in the same time, but typing M-x shell a second time just opens me the same shell window.
Is there a way to have different shell windows?
C-u M-x shell will do it.
It will prompt for a name for the new shell, just hit return for the default (which will be something like *shell*<2>.
Also works with eshell.
Another trick, if you use eshell: just as M-x eshell takes you back to *eshell* (rather than starting a new eshell), if you use a numeric prefix argument it will take you to that eshell buffer. For instance, C-3M-xeshell will take you to *eshell*<3>. Sadly if you use shell (rather than eshell), this trick doesn't seem to work (in my Emacs 24.0.50.1 at least.)
You can rename the buffer of your shell with M-x rename-buffer. Then you will be able to launch a second shell.
Look at MultiTerm, it makes managing multiple terminals in Emacs much easier.
After more than four years, I see that some people are still looking at this issue sometimes, so I will publish a quick function I wrote to load a shell and ask for its name. That way you can name a shell "sort-files" if it is dedicated to sorting files and another one "hive" if it's dedicated to run hive queries. I use that everyday now (on emacs 24):
(defun create-shell ()
"creates a shell with a given name"
(interactive);; "Prompt\n shell name:")
(let ((shell-name (read-string "shell name: " nil)))
(shell (concat "*" shell-name "*"))))
It might also be useful to use a screen-like interface to your shells. I've written my own, but there are others out there, like EmacsScreen.
This will autogenerate a new shell instance in whatever buffer you happen to be using; bind it to M-S or somethings like that and instant joy:
(defun new-shell ()
(interactive)
(let (
(currentbuf (get-buffer-window (current-buffer)))
(newbuf (generate-new-buffer-name "*shell*"))
)
(generate-new-buffer newbuf)
(set-window-dedicated-p currentbuf nil)
(set-window-buffer currentbuf newbuf)
(shell newbuf)
)
)
Many thanks to phils for recommending a rewrite using let, even though the result is even more awful parentheses...:\
This will open a new shell each time you invoke the function and rename it automatically if needed.
The added plus is if you are editing files remotely (dired/tramp...), this will open a shell on the remote host and rename it automatically with the remote hostname:
(defun ggshell (&optional buffer)
(interactive)
(let* (
(tramp-path (when (tramp-tramp-file-p default-directory)
(tramp-dissect-file-name default-directory)))
(host (tramp-file-name-real-host tramp-path))
(user (if (tramp-file-name-user tramp-path)
(format "%s#" (tramp-file-name-user tramp-path)) ""))
(new-buffer-nameA (format "*shell:%s*" host))
(new-buffer-nameB (generate-new-buffer-name new-buffer-nameA))
(currentbuf (get-buffer-window (current-buffer)))
)
(generate-new-buffer new-buffer-nameB)
(set-window-dedicated-p currentbuf nil)
(set-window-buffer currentbuf new-buffer-nameB)
(shell new-buffer-nameB)
))

Emacs + tramp + plink

I'm trying to get emacs tramp running under Windows XP to work over putty plink on an Amazon EC2 instance. The documentation for doing this is sparse. I can find partial documentation, but none that addresses all the steps required to get this working.
Can anyone provide a walk through, or a pointer to a walk through?
(add-to-list 'load-path
(expand-file-name "C:/tools/emacsw32/emacs/lisp/tramp/lisp"))
(require 'tramp)
;(setq tramp-chunksize "500")
(setq tramp-default-method "plink")
from my dot-emacs file. If I find more notes, I shall add them here.
I'll assume you have a GNU/Linux server you want to access, a username and a .ppk file. Also, Emacs 24.4+.
First set up server in PuTTY Configuration
In section Session, specify Host Name, for example username#server.
Go to section Connection > SSH > Auth and Browse for your "Private key file for authentication".
Back to section Session, name your Saved Sessions, for example putty-test, and click Save button.
Check your connection by clicking the Open button. If it works, you can close these now.
Next, head to your Emacs.
Make sure Emacs knows where your plink.exe is. One way is to just inform Emacs directly in your .emacs, for instance I have at the moment,
(setenv "PATH" (concat "c:/Users/Brady/Documents/putty/;" (getenv "PATH")))
Simply type C-x C-f //plink:putty-test:/ RET. Wait a moment while it connects, and window will open to dired buffer on the remote ~/ directory.
This worked for me on :
Windows 10
Emacs found at https://sourceforge.net/projects/emacsbinw64/files/release/.
cygwin64
Putty.
https://github.com/d5884/fakecygpty
The changes from the original tramp-sh.el is
for cygwin, use fakecygpty with ssh and change the prompt to ##
for plink, remove -ssh option
I have also renamed these method with w to differentiate it.
(when (string-equal system-type "windows-nt")
(add-to-list 'tramp-methods
`("sshw"
(tramp-login-program "fakecygpty ssh")
;; ("%h") must be a single element, see `tramp-compute-multi-hops'.
(tramp-login-args (("-l" "%u" "-o \"StrictHostKeyChecking=no\"") ("-P" "%p") ("-t")
("%h") ("\"")
(,(format
"env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
tramp-terminal-type
"##"))
("/bin/sh") ("\"")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-login ("-l"))
(tramp-remote-shell-args ("-c"))
(tramp-default-port 22))
)
(add-to-list 'tramp-methods
`("plinkw"
(tramp-login-program "plink")
;; ("%h") must be a single element, see `tramp-compute-multi-hops'.
(tramp-login-args (("-l" "%u") ("-P" "%p") ("-t")
("%h") ("\"")
(,(format
"env 'TERM=%s' 'PROMPT_COMMAND=' 'PS1=%s'"
tramp-terminal-type
"$"))
("/bin/sh") ("\"")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-login ("-l"))
(tramp-remote-shell-args ("-c"))
(tramp-default-port 22))
)
)