I have a process that prints some lines of text running in the background. If I start ssh, the newline characters don't work properly.
user@localhost:~$ { sleep 5; echo -e "1\n2\n3" ; } &
[1] 26215
user@localhost:~$ 1
2
3
user@localhost:~$ { sleep 5; echo -e "1\n2\n3" ; } &
user@localhost:~$ ssh localhost # quickly
user@localhost:~$ 1
2
3
I would expect 2 and 3 to start at the beginning of a newline regardless of whether ssh is running or not. Can someone explain what's happening here? Is there a way to fix things so newlines still work?
Oddly, if I throw some \r
into the mix the newlines seem to work again, although I need to replace the default echo newline with a \r
too.
user@localhost:~$ { sleep 5; echo -en "1\r\n2\r\n3\r\n" ; } &
[1] 7066
user@localhost:~$ 1
2
3
By default in an interactive shell the tty/pty is in canonical mode and \n
written to the tty will be automatically converted to \r\n
.
When you ssh to a remote server to start an interactive shell, ssh will change the local tty to raw mode (or non-canonical mode) and in raw mode \n
will not be converted to \r\n
.
See the following example (highlighted some part with ^
chars):
$ tty
/dev/pts/2
$ stty -a -F /dev/pts/2
speed 38400 baud; rows 43; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = <undef>; susp = ^Z;
rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
^^^^^ ^^^^^
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
^^^^^^
echoctl echoke -flusho -extproc
$
$ ssh -t 127.0.0.1 bash --norc
bash-5.1# tty
/dev/pts/13
bash-5.1# stty -a -F /dev/pts/2
speed 38400 baud; rows 43; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = <undef>; susp = ^Z;
rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff
-iuclc -ixany -imaxbel iutf8
-opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
^^^^^^
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt
^^^^^^^
echoctl echoke -flusho -extproc
bash-5.1#
As you've found out, to force the \r\n
behavior you can explicitly use \r\n
:
printf '1\r\n2\r\n3\r\n'
You can see stty's manual for more details about the misc flags.