ssh host tail -f file
ssh client connects to the
sshd server on
host over a TCP connection.
tail -f with its stdout redirected to a pipe.
sshd reads what's coming from the other end of the pipe and encapsulates it in the sshd protocol to send to the
ssh client. (with
tail stdout would have been the socket directly, but
sshd adds encryption and is able to multiplex several streams (like for port/agent/X11/tunnel redirection, stderr) on a single TCP connection so has to resort to pipes).
When you press CTRL-C, a SIGINT is sent to the
ssh client. That causes
ssh to die. Upon dying the TCP connection is closed. And therefore, on
sshd dies as well.
tail is not killed, but its stdout is now a pipe with no reader at the other end. So, the next time it writes something to its stdout, it will receive a SIGPIPE and die.
ssh -t host 'tail -f file'
It's the same thing except that instead of being with a pipe, the communication between
tail is via a pseudo-terminal.
tail's stdout is a slave pseudo-terminal (like
/dev/pts/12) and whatever
tail write there is
read on the master side (possibly modified by the tty line discipline) by
sshd and sent encapsulated to the
On the client side, with
ssh puts the terminal in
raw mode. In particular, that disables the terminal canonical mode and terminal signal handling.
So, when you press Ctrl+C, instead of the client's terminal line discipline sending a SIGINT to the
ssh job, that just sends the
^C character over the connection to
sshd writes that
^C to the master side of the remote terminal. And the line discipline of the remote terminal sends a
tail then dies, and
sshd exits and closes the connection and
ssh terminates (if it's not otherwise still busy with port forwardings or other).
-t, if the
ssh client dies (for instance if you enter
~.), the connection is closed and
sshd dies. As a result, a SIGHUP will be sent to
Now, beware that using
-t has side effects. For instance, with the default terminal settings,
\n characters are converted to
\r\n and more things may happen depending on the remote system, so you may want to issue a
stty -opost (to disable output post-processing) on the remote host if that output is not intended for a terminal:
$ ssh localhost 'echo x' | hd
00000000 78 0a |x.|
$ ssh -t localhost 'echo x' | hd
00000000 78 0d 0a |x..|
$ ssh -t localhost 'stty -opost; echo x' | hd
00000000 78 0a |x.|
Another drawback of using
-tt is that stdout and stderr are not differentiated on the client. Both the stdout and stderr of the remote command will be written to the
ssh client's stdout:
$ ssh localhost ls /x | wc -l
ls: cannot access /x: No such file or directory
$ ssh -t localhost ls /x | wc -l