TRAMP supports starting new running processes on the remote host for discovering remote file names. Emacs packages on the remote host need no specific modifications for TRAMP’s use.
This type of integration does not work with the ftp method,
and does not support the pty association as specified in
start-file-process work on the remote
host when the variable
default-directory is remote:
(let ((default-directory "/ssh:remote.host:")) (start-file-process "grep" (get-buffer-create "*grep*") "/bin/sh" "-c" "grep -e tramp *"))
For a local process,
process-file returns either the exit code
of the process, or a string describing a signal, when the process has
been interrupted. Since it cannot be determined reliably whether a
remote process has been interrupted,
process-file will always
returns the exit code for it. When the user option
process-file-return-signal-string is non-
process-file treats all exit codes greater than 128 as an
indication that the process has been interrupted, and returns a
This remote process handling does not apply to GVFS (see
GVFS-based external methods) because the remote file system is mounted on
the local host and TRAMP accesses it by changing the
TRAMP starts a remote process when a command is executed in a
remote file or directory buffer. As of now, these packages have been
integrated to work with TRAMP: shell.el,
eshell.el, compile.el (commands like
grep) and gud.el (
TRAMP always modifies the
variable for remote processes. By default, this environment variable
shows the Emacs version. TRAMP adds its own version string,
so it looks like ‘27.2,tramp:188.8.131.52’. However, other packages
might also add their name to this environment variable, like
For TRAMP to find the command on the remote, it must be
accessible through the default search path as setup by TRAMP
upon first connection. Alternatively, use an absolute path or extend
tramp-remote-path (see How TRAMP finds and uses programs on the remote host):
(add-to-list 'tramp-remote-path "~/bin") (add-to-list 'tramp-remote-path "/appli/pub/bin")
Customize user option
suit the remote program’s environment for the remote host.
tramp-remote-process-environment is a list of strings
structured similar to
process-environment, where each element
is a string of the form ‘ENVVARNAME=VALUE’.
To avoid any conflicts with local host environment variables set through local configuration files, such as ~/.profile, use ‘ENVVARNAME=’ to unset them for the remote environment.
add-to-list to add entries:
(add-to-list 'tramp-remote-process-environment "JAVA_HOME=/opt/java")
Modifying or deleting already existing values in the
tramp-remote-process-environment list may not be feasible on
restricted remote hosts. For example, some system administrators
HISTORY environment variable. To accommodate
such restrictions when using TRAMP, fix the
tramp-remote-process-environment by the following code in the
local .emacs file:
(let ((process-environment tramp-remote-process-environment)) (setenv "HISTORY" nil) (setq tramp-remote-process-environment process-environment))
ENV environment variable instructs some shells to
read an initialization file. By default, TRAMP disables
this. You can override this behavior by evaluating
(let ((process-environment tramp-remote-process-environment)) (setenv "ENV" "$HOME/.profile") (setq tramp-remote-process-environment process-environment))
In addition to
tramp-remote-process-environment, you can set
environment variables for individual remote process calls by
process-environment. TRAMP applies any
entries not present in the global default value of
tramp-remote-process-environment settings, if they conflict).
(let ((process-environment (cons "HGPLAIN=1" process-environment))) (process-file …))
Let-binding in this way works regardless of whether the process to be
called is local or remote, since TRAMP would add just the
HGPLAIN setting and local processes would take whole value of
process-environment along with the new value of
For integrating other Emacs packages so TRAMP can execute remotely, please file a bug report. See Reporting Bugs and Problems.
shellon a remote host
shell-commandon a remote host
eshellon a remote host
To allow a remote program to create an X11 window on the local host,
DISPLAY environment variable for the remote host as
follows in the local .emacs file:
(add-to-list 'tramp-remote-process-environment (format "DISPLAY=%s" (getenv "DISPLAY")))
(getenv "DISPLAY") should return a recognizable name for the
local host that the remote host can redirect X11 window
interactions. If querying for a recognizable name is not possible for
whatever reason, then replace
(getenv "DISPLAY") with a
hard-coded, fixed name. Note that using
:0 for X11 display name
here will not work as expected.
An alternate approach is specify ForwardX11 yes or ForwardX11Trusted yes in ~/.ssh/config on the local host.
shellon a remote host
explicit-shell-file-name to the appropriate shell name
when using TRAMP between two hosts with different operating
systems, such as ‘windows-nt’ and ‘gnu/linux’. This option
ensures the correct name of the remote shell program.
explicit-shell-file-name is equal to
shell interactively will prompt for a shell name.
Starting with Emacs 26, you could use connection-local variables
for setting different values of
different remote hosts.
(connection-local-set-profile-variables 'remote-bash '((explicit-shell-file-name . "/bin/bash") (explicit-bash-args . ("-i"))))
(connection-local-set-profile-variables 'remote-ksh '((explicit-shell-file-name . "/bin/ksh") (explicit-ksh-args . ("-i"))))
(connection-local-set-profiles '(:application tramp :protocol "ssh" :machine "localhost") 'remote-bash)
(connection-local-set-profiles `(:application tramp :protocol "sudo" :user "root" :machine ,(system-name)) 'remote-ksh)
shell-commandon a remote host
shell-command executes commands synchronously or asynchronously
on remote hosts and displays output in buffers on the local
C-x C-f /sudo:: RET M-& tail -f /var/log/syslog.log RET
tail command outputs continuously to the local buffer whose
name is the value of the variable
M-x auto-revert-tail-mode RET runs similarly showing continuous output.
shell-command uses the user option
shell-command-switch in order to determine which
shell to run. For remote hosts, their default values are
/bin/sh and -c, respectively (except for the
adb method, which uses /system/bin/sh). Like the
variables in the previous section, these variables can be changed via
If Emacs supports the user option
(since Emacs 27), TRAMP cares about its value for
asynchronous shell commands. It specifies the number of display
columns for command output. For synchronous shell commands, a similar
effect can be achieved by adding the environment variable
eshellon a remote host
TRAMP is integrated into eshell.el, which enables
interactive eshell sessions on remote hosts at the command prompt.
You must add the module
eshell-modules-list. Here’s a sample interaction after opening
M-x eshell RET on a remote host:
~ $ cd /sudo::/etc RET /sudo:root@host:/etc $ hostname RET host /sudo:root@host:/etc $ id RET uid=0(root) gid=0(root) groups=0(root) /sudo:root@host:/etc $ find-file shadow RET #<buffer shadow> /sudo:root@host:/etc $
eshell added custom
sudo commands that set
the default directory correctly for the *eshell* buffer.
TRAMP silently updates
with an entry for this directory (see Connecting to a remote host using multiple hops):
~ $ cd /ssh:user@remotehost:/etc RET /ssh:user@remotehost:/etc $ find-file shadow RET File is not readable: /ssh:user@remotehost:/etc/shadow /ssh:user@remotehost:/etc $ sudo find-file shadow RET #<buffer shadow>
/ssh:user@remotehost:/etc $ su - RET /su:root@remotehost:/root $ id RET uid=0(root) gid=0(root) groups=0(root) /su:root@remotehost:/root $
gud.el provides a unified interface to symbolic
TRAMP can run debug on remote hosts by calling
with a remote file name:
M-x gdb RET Run gdb (like this): gdb -i=mi /ssh:host:~/myprog RET
Since the remote
gdb-inferior processes do not
belong to the same process group on the remote host, there will be a
warning, which can be ignored:
&"warning: GDB: Failed to set controlling terminal: Operation not permitted\n"
As consequence, there will be restrictions in I/O of the process to be debugged.
Relative file names are based on the remote default directory. When myprog.pl exists in /ssh:host:/home/user, valid calls include:
M-x perldb RET Run perldb (like this): perl -d myprog.pl RET
Just the local part of a remote file name, such as
/home/user/myprog.pl, is not possible.
Arguments of the program to be debugged must be literal, can take relative or absolute paths, but not remote paths.
winexe runs processes on a remote MS Windows host, and
TRAMP can use it for
tramp-smb-winexe-program specifies the local
command. Powershell V2.0 on the remote host is required to run
processes triggered from TRAMP.
explicit-*-args have to
be set properly so M-x shell RET can open a proper remote
shell on a MS Windows host. To open
cmd, set it as follows:
(setq explicit-shell-file-name "cmd" explicit-cmd-args '("/q"))
powershell as a remote shell, use this:
(setq explicit-shell-file-name "powershell" explicit-powershell-args '("-file" "-"))
Asynchronous processes behave differently based on whether they use a
pseudo tty or not. This is controlled by the variable
process-connection-type, which can be
(use a pseudo tty), or
pipe (don’t use one).
TRAMP is based on running shells on the remote host, which
requires a pseudo tty. Therefore, it declares the variable
tramp-process-connection-type, which carries this information
for remote processes. Its default value is
t, and there is no
need to change it. The name of the remote pseudo tty is returned by
If a remote process, started by
not use a pseudo tty, this can be requested by setting
pipe. There is
still a pseudo tty for the started process, but some terminal
properties are changed, like suppressing translation of carriage
return characters into newline.
make-process allows controlling this explicitly by
:connection-type keyword. If this keyword is not
used, the value of
process-connection-type is applied instead.
TRAMP’s implementation of
start-file-process requires a serious overhead for
initialization, every process invocation. This is needed for handling
interactive dialogues when connecting the remote host (like providing
a password), and initial environment setup.
Sometimes, this is not needed. Instead of starting a remote shell and
running the command afterwards, it is sufficient to run the command
directly. TRAMP supports this by an alternative
This is triggered by the connection property
"direct-async-process", See Setting own connection related information,
which must be set to a non-
nil value. Example:
(add-to-list 'tramp-connection-properties (list (regexp-quote "/ssh:user@host:") "direct-async-process" t))
Using direct asynchronous processes in TRAMP is not possible, if the remote host is connected via multiple hops (see Connecting to a remote host using multiple hops). In this case, TRAMP falls back to its classical implementation.
Furthermore, this approach has the following limitations:
ssh-agent, using public key authentication, or using ControlMaster options.
In order to gain even more performance, it is recommended to bind
tramp-verbose to 0 when running
start-file-process. Furthermore, you might set
nil in order to
bypass TRAMP’s handling of the ControlMaster options,
and use your own settings in ~/.ssh/config.