Unix tools: persistent TUIs

One of the beautiful things about the CLI paradigm is how amenable it is to using remote computers exactly the same way you do your own.

TL;DR: tmux is a large system for running persistent shell settings which works great on remote hosts, mosh is very simply a drop-in replacement for ssh which can survive network outages.

Many of us had an "ah hah" moment when discovering that entering in text commands and reading the text output that comes back works just as well if those commands are sent, and that output received, across a network connection. And SSH is a really well-designed, straightforward piece of software that just perfectly disappears - sometimes I can stare at a shell and not even know *where* it is.

But then we hit a snag: unlike a local shell, that ssh session is subject to the stability of your network connection. Running a large script that takes a long time? Getting engrossed in multiple conversations over IRC? Hope you're on wired ethernet ;)

There are tools that address this issue though, so here are some ways to smooth out that use-case.

tmux: the terminal multiplexer

Tmux is one of those "Othello" programs: it takes a minute to learn, a lifetime to master. The core functionality is pretty basic: a server keeps one or more shell sessions running, a client gives you a window into one of those sessions at a time. This solves our core problem of inconsistent connectivity because we only become disconnected from the client, meanwhile our shell session is still happily sitting there under the tmux server process, waiting for us to reconnect to it with a fresh client whenever we return. You control tmux itself from without via the tmux(1) command, and from within by a prefix keybinding (ctrl-b by default) which causes the next keystroke to be a hotkey sending a control command to the current tmux session.

That was a lot, here's a simpler example.

Get into a new tmux session:

$ tmux new-session

The new-session command, well, creates a new session (though "session" here is a tmux construct, one of which may contain multiple shells), creating a server on-demand if one wasn't running for your user already. You'll notice a green bar appeared across the bottom of your terminal - that is tmux's status bar.

Let's just put something in here to behave like a long-running cli program:

$ for i in $(seq 120); do echo $i; sleep 5; done

That will just print consecutive numbers, one every 5 seconds, for the next 10 minutes. That'll do. Now with that still running, type ctrl-b and then "d". The "d" instructs the tmux client to "detach" from the server. You'll be back in the shell you started in, from where you initially got the tmux session started. At this point, if you are currently doing all this on a remote machine, you could ctrl-d and close your whole SSH session, and your program would continue running on the remote machine. Do that if you like, but once back with a shell on the same host as before, now run the command to re-attach to an existing tmux session:

$ tmux attach

You should see the tmux status bar at the bottom again, and your for-loop still going, perhaps with a few new lines of output that showed up while you were away! If you ctrl-c to stop that loop, and ctrl-d to close that shell, you should be back in your shell session outside of tmux (looking at "tmux attach" as your last command entered). When you close the last shell in a tmux session it closes that session, and behind the scenes, when you end the last session it shuts down the whole server process.

So there you have everything you need to keep one shell persistent even when you close your laptop and walk out of the coffee shop :)

There is so much more to learn though. You can start multiple tmux sessions, or manage multiple shells within a tmux session, you can split the screen and view multiple shells at once, and all of this is extremely configurable and scriptable. We won't go into those here though, check out a dedicated post on the subject like this one:

=> "A gentle introduction to tmux" from Hackernoon

One last comment about tmux though, an obligatory shout-out to the real creator of terminal multiplexing: screen(1). This was the original program that did the same thing, it's just very long in the tooth these days and surpassed in every way by tmux.

mosh: the mobile shell

Mosh is usable as a drop-in replacement for ssh which runs your shell session on the remote host resilient to unintentional disconnects, and transparently re-connects you. So for example, just closing your laptop lid will interrupt any network connections such as your remote shell, but if it's mosh then when you open it back up again it'll simply reconnect and show you the same remote shell again. There's really very little to talk about here :)

Unlike tmux or screen, however, since it's not explicit about active sessions/windows/etc, if you do *intentionally* disconnect, for instance with ctrl-d, it will end the remote shell as well. So you can't, for instance, close your local terminal window and fully quit your terminal program and expect your remote session to still be there when you come back. But if you want to use terminal windows like browser tabs and leave them open all the time, mosh makes that possible.

why though?

For the same reason we don't close our local programs: as we move around making use of different programs it's easier to alt-tab/cmd-tab over to the already-active program than to start it back up from scratch. And sometimes in those user interfaces (perhaps even more so in TUIs) valuable context gets built up in the session over time, and you shouldn't have to lose that every time you put your laptop to sleep.

Chat clients are a great example. Heavy command-line users and IRC users make a deeply intersecting venn diagram, and there are very good TUI IRC clients in weechat and irssi. Staying connected to your chat network by virtue of a server's internet connection can be a great way to not miss anything. Keep the IRC client running in a tmux always keeping up with the ongoing conversations in your channels, and reconnect and catch up at your leisure. Even though they don't have the same ongoing context, I tend to run email and newsgroup clients in tmux as well. I can also leave a vim session running when I'm in the middle of editing something, knowing I can come back to it.

In fact, I use both tmux and mosh. Tmux because it's a complete multiple-shell-management tool that keeps me organized on a remote host, and I get into that tmux session via mosh because - why not? It's just as easy to start as ssh, and there's no reason to need to reconnect yourself all the time.