What is the benefit of not allocating a terminal in ssh?
The primary difference is the concept of interactivity. It's similar to running commands locally inside of a script, vs. typing them out yourself. It's different in that a remote command must choose a default, and non-interactive is safest. (and usually most honest)
- If a PTY is allocated, applications can detect this and know that it's safe to prompt the user for additional input without breaking things. There are many programs that will skip the step of prompting the user for input if there is no terminal present, and that's a good thing. It would cause scripts to hang unnecessarily otherwise.
- Your input will be sent to the remote server for the duration of the command. This includes control sequences. While a
Ctrl-cbreak would normally cause a loop on the ssh command to break immediately, your control sequences will instead be sent to the remote server. This results in a need to "hammer" the keystroke to ensure that it arrives when control leaves the ssh command, but before the next ssh command begins.
I would caution against using
ssh -t in unattended scripts, such as crons. A non-interactive shell asking a remote command to behave interactively for input is asking for all kinds of trouble.
You can also test for the presence of a terminal in your own shell scripts. To test STDIN with newer versions of bash:
# fd 0 is STDIN [ -t 0 ]; echo $?
- When aliasing
ssh -t, you can expect to get an extra carriage return in your line ends. It may not be visible to you, but it's there; it will show up as
^Mwhen piped to
cat -e. You must then expend the additional effort of ensuring that this control code does not get assigned to your variables, particularly if you're going to insert that output into a database.
- There is also the risk that programs will assume they can render output that is not friendly for file redirection. Normally if you were to redirect STDOUT to a file, the program would recognize that your STDOUT is not a terminal and omit any color codes. If the STDOUT redirection is from the output of the ssh client and the there is a PTY associated with the remote end of the client, the remote programs cannot make such a distinction and you will end up with terminal garbage in your output file. Redirecting output to a file on the remote end of the connection should still work as expected.
Here is the same bash test as earlier, but for STDOUT:
# fd 1 is STDOUT [ -t 1 ]; echo $?
While it's possible to work around these issues, you're inevitably going to forget to design scripts around them. All of us do at some point. Your team members may also not realize/remember that this alias is in place, which will in turn create problems for you when they write scripts that use your alias.
ssh -t is very much a case where you'll be violating the design principle of least surprise; people will be encountering problems they do not expect and may not understand what is causing them.
SSH escape/control characters and transfer of binary files
One advantage that hasn’t been mentioned in the other answers is that when operating without a pseudo-terminal, the SSH escape characters such as
~C are not supported; this makes it safe for programs to transfer binary files which may contain these and other control characters.
Without a pseudo-terminal the characters are transferred to the remote host “as is”:
$ printf "one\ntwo\n~Cthree\n" | ssh [email protected] tee 1 one two ~Cthree
If you try to forcing the allocation of a pseudo-terminal, the inclusion of the
~C causes the
ssh> prompt to be printed to allow the user to enter an SSH command, interrupting the transfer.
$ printf "one\ntwo\n~Cthree\n" | ssh -tt [email protected] tee 2 ssh> one two three one two three
~. sequence is worse as it results in no data being transferred:
$ printf "one\ntwo\n~.three\n" | ssh -tt [email protected] tee 2 Connection to host closed.
Software flow control
Software flow control characters (XON/XOFF) may also be treated specially when a pseudo-terminal is allocated.
$ printf "one\ntwo\n^Sthree\n" | ssh [email protected] tee 1 one two three $ ssh [email protected] cat -vet 1 one$ two$ ^Sthree$
With a pseudo-terminal, the
Ctrl-S character is interpreted as a signal to pause the input stream so no more data can be sent after this character is encountered (unless it’s followed by a
Ctrl-Q character later in the input stream).
In this case, forcing the allocation of a pseudo-terminal results in the file on the remote end being empty.
$ printf "one\ntwo\n^Sthree\n" | ssh -tt [email protected] tee 2 one two
In this case, forcing the allocation of a pseudo-terminal results in the file on the remote end containing all three lines but without the control characters:
$ printf "one\ntwo\n^Sthree^Q\n" | ssh -tt [email protected] tee 2 one two three one two three $ ssh [email protected] cat -vet 2 one$ two$ three$
Conversion of line-ending characters
With a pseudo-terminal, Line Feed characters (decimal 10, hex
0A in ASCII) are also translated to
CRLF sequences (hex
0D0A in ASCII) .
From the previous example:
$ ssh -t [email protected] cat 1 | cat -vet one^M$ two^M$ ^Sthree^M$ Connection to host closed.
Copy a binary file using a pseudo-terminal
$ ssh -t [email protected]_host 'cat /usr/bin/free' > ~/free Connection to remote_host closed.
Copy a binary file without using a pseudo-terminal:
$ ssh [email protected]_host 'cat /usr/bin/free' > ~/free2
The two files aren’t the same:
$ diff ~/free* Binary files /home/anthony/free and /home/anthony/free2 differ
The one which was copied with a pseudo-terminal is corrupted:
$ chmod +x ~/free* $ ./free Segmentation fault
while the other isn’t:
$ ./free2 total used free shared buffers cached Mem: 2065496 1980876 84620 0 48264 1502444 -/+ buffers/cache: 430168 1635328 Swap: 4128760 112 4128648
Transferring files over SSH
This is particularly important for programs such as
rsync which use SSH for data transfer. This detailed description of how the SCP protocol works explains how the SCP protocol consists of a mixture of textual protocol messages and binary file data.
OpenSSH helps protects you from yourself
It’s worth noting that even if the
-t flag is used, the OpenSSH
ssh client will refuse to allocate a pseudo-terminal if it detects that its
stdin stream is not a terminal:
$ echo testing | ssh -t [email protected]_host 'echo $TERM' Pseudo-terminal will not be allocated because stdin is not a terminal. dumb
You can still force the OpenSSH client to allocate a pseudo-terminal with
$ echo testing | ssh -tt [email protected]_host 'echo $TERM' xterm
In either case, it (sensibly) doesn’t care if
stderr are redirected:
$ ssh -t [email protected]_host 'echo $TERM' >| ssh_output Connection to remote_host closed.
On remote host we have to do with this setting:
/etc/sudoers ... Defaults requiretty
$ ssh -T [email protected] echo -e 'foo\\nbar' | cat -e foo$ bar$
And with sudo
$ ssh -T [email protected] sudo echo -e 'foo\\nbar' | cat -e sudo: sorry, you must have a tty to run sudo
With sudo we get the extra carriage return
$ ssh -t [email protected] sudo echo -e 'foo\\nbar' | cat -e foo^M$ bar^M$ Connection to localhost closed.
The solution is to disable the translate newline to carriage return-newline with
$ ssh -t [email protected] stty -onlcr\; sudo echo -e 'foo\\nbar' | cat -e foo$ bar$ Connection to localhost closed.