Next: , Previous: Remote Programs, Up: Configuration

4.15 Remote shell setup hints

As explained in the Overview section, tramp connects to the remote host and talks to the shell it finds there. Of course, when you log in, the shell executes its init files. Suppose your init file requires you to enter the birth date of your mother; clearly tramp does not know this and hence fails to log you in to that host.

There are different possible strategies for pursuing this problem. One strategy is to enable tramp to deal with all possible situations. This is a losing battle, since it is not possible to deal with all situations. The other strategy is to require you to set up the remote host such that it behaves like tramp expects. This might be inconvenient because you have to invest a lot of effort into shell setup before you can begin to use tramp.

The package, therefore, pursues a combined approach. It tries to figure out some of the more common setups, and only requires you to avoid really exotic stuff. For example, it looks through a list of directories to find some programs on the remote host. And also, it knows that it is not obvious how to check whether a file exists, and therefore it tries different possibilities. (On some hosts and shells, the command test -e does the trick, on some hosts the shell builtin doesn't work but the program /usr/bin/test -e or /bin/test -e works. And on still other hosts, ls -d is the right way to do this.)

Below you find a discussion of a few things that tramp does not deal with, and that you therefore have to set up correctly.

shell-prompt-pattern
After logging in to the remote host, tramp has to wait for the remote shell startup to finish before it can send commands to the remote shell. The strategy here is to wait for the shell prompt. In order to recognize the shell prompt, the variable shell-prompt-pattern has to be set correctly to recognize the shell prompt on the remote host.

Note that tramp requires the match for shell-prompt-pattern to be at the end of the buffer. Many people have something like the following as the value for the variable: "^[^>$][>$] *". Now suppose your shell prompt is a <b> c $ . In this case, tramp recognizes the > character as the end of the prompt, but it is not at the end of the buffer.

tramp-shell-prompt-pattern
This regular expression is used by tramp in the same way as shell-prompt-pattern, to match prompts from the remote shell. This second variable exists because the prompt from the remote shell might be different from the prompt from a local shell—after all, the whole point of tramp is to log in to remote hosts as a different user. The default value of tramp-shell-prompt-pattern is the same as the default value of shell-prompt-pattern, which is reported to work well in many circumstances.
tramp-password-prompt-regexp
During login, tramp might be forced to enter a password or a passphrase. The difference between both is that a password is requested from the shell on the remote host, while a passphrase is needed for accessing local authentication information, like your ssh key.

tramp-password-prompt-regexp handles the detection of such requests for English environments. When you use another localization of your (local or remote) host, you might need to adapt this. Example:

          (setq
            tramp-password-prompt-regexp
              (concat
                "^.*"
                (regexp-opt
                  '("passphrase" "Passphrase"
                    ;; English
                    "password" "Password"
                    ;; Deutsch
                    "passwort" "Passwort"
                    ;; Français
                    "mot de passe" "Mot de passe") t)
                ".*:\0? *"))

In parallel, it might also be necessary to adapt tramp-wrong-passwd-regexp.

tset and other questions
Some people invoke the tset program from their shell startup scripts which asks the user about the terminal type of the shell. Maybe some shells ask other questions when they are started. tramp does not know how to answer these questions. There are two approaches for dealing with this problem. One approach is to take care that the shell does not ask any questions when invoked from tramp. You can do this by checking the TERM environment variable, it will be set to dumb when connecting.

The variable tramp-terminal-type can be used to change this value to dumb.

The other approach is to teach tramp about these questions. See the variable tramp-actions-before-shell. Example:

          (defconst my-tramp-prompt-regexp
            (concat (regexp-opt '("Enter the birth date of your mother:") t)
                    "\\s-*")
            "Regular expression matching my login prompt question.")
          
          (defun my-tramp-action (proc vec)
            "Enter \"19000101\" in order to give a correct answer."
            (save-window-excursion
              (with-current-buffer (tramp-get-connection-buffer vec)
                (tramp-message vec 6 "\n%s" (buffer-string))
                (tramp-send-string vec "19000101"))))
          
          (add-to-list 'tramp-actions-before-shell
                       '(my-tramp-prompt-regexp my-tramp-action))

Environment variables named like users in .profile
If you have a user named frumple and set the variable FRUMPLE in your shell environment, then this might cause trouble. Maybe rename the variable to FRUMPLE_DIR or the like.

This weird effect was actually reported by a tramp user!

Non-Bourne commands in .profile
After logging in to the remote host, tramp issues the command exec /bin/sh. (Actually, the command is slightly different.) When /bin/sh is executed, it reads some init files, such as ~/.shrc or ~/.profile.

Now, some people have a login shell which is not /bin/sh but a Bourne-ish shell such as bash or ksh. Some of these people might put their shell setup into the files ~/.shrc or ~/.profile. This way, it is possible for non-Bourne constructs to end up in those files. Then, exec /bin/sh might cause the Bourne shell to barf on those constructs.

As an example, imagine somebody putting export FOO=bar into the file ~/.profile. The standard Bourne shell does not understand this syntax and will emit a syntax error when it reaches this line.

Another example is the tilde (~) character, say when adding ~/bin to PATH. Many Bourne shells will not expand this character, and since there is usually no directory whose name consists of the single character tilde, strange things will happen.

What can you do about this?

Well, one possibility is to make sure that everything in ~/.shrc and ~/.profile on all remote hosts is Bourne-compatible. In the above example, instead of export FOO=bar, you might use FOO=bar; export FOO instead.

The other possibility is to put your non-Bourne shell setup into some other files. For example, bash reads the file ~/.bash_profile instead of ~/.profile, if the former exists. So bash aficionados just rename their ~/.profile to ~/.bash_profile on all remote hosts, and Bob's your uncle.

The tramp developers would like to circumvent this problem, so if you have an idea about it, please tell us. However, we are afraid it is not that simple: before saying exec /bin/sh, tramp does not know which kind of shell it might be talking to. It could be a Bourne-ish shell like ksh or bash, or it could be a csh derivative like tcsh, or it could be zsh, or even rc. If the shell is Bourne-ish already, then it might be prudent to omit the exec /bin/sh step. But how to find out if the shell is Bourne-ish?

Interactive shell prompt
tramp redefines the shell prompt in order to parse the shell's output robustly. When calling an interactive shell by M-x shell, this doesn't look nice.

You can redefine the shell prompt by checking the environment variable INSIDE_EMACS, which is set by tramp, in your startup script ~/.emacs_SHELLNAME. SHELLNAME might be the string bash or similar, in case of doubt you could set it the environment variable ESHELL in your .emacs:

          (setenv "ESHELL" "bash")

Your file ~/.emacs_SHELLNAME could contain code like

          # Reset the prompt for remote Tramp shells.
          if [ "${INSIDE_EMACS/*tramp*/tramp}" == "tramp" ] ; then
             PS1="[\u@\h \w]$ "
          fi