I spend almost all of my time in a terminal inside of a GNUscreensession. Over the years, I’ve form fitted my usage ofscreenthrough a set of shell functions. Here, I talk a bit about why, how, and ultimately share my tool. I hope it inspires you to tailor-fit your favorite CLI tools.
I spend most of my (productive) digital time on the command line. I love its
composability, automatability, and flexibility. My primary text editor is vim.
I hate interacting with graphical git interfaces. And only rarely do I turn to
graphical file managers for organizing my file system.
Early on in my technical journey, I compartmentalized my purpose-driven shell sessions through multiple windows or tabs. Eventually I reached a point where I wanted to liberate even that from the confines of the terminal software I was using. This would ensure a glitch or bug in the terminal emulator wouldn’t result in my current shell session being lost. And, I wouldn’t tie my flows to a given terminal, making them even more portable. So, I ventured into the world of terminal multiplexers (command line window managers of a sort).
The two most popular multiplexers are tmux and GNU’s screen, the
latter taking second place to the programming language Go as the worst technology
to try to search the Internet for. tmux was actually created to fix many of the
deficiencies of screen. Yet, I still ended up on screen ostensibly for its ubiquity,
but I was admittedly significantly motivated by my inability to figure out how to get
rid of tmux’s status line.
Last year, there were some pretty big bugs found in
screen, reported as CVEs (Common Vulnerabilities and Exposures) have revealed some weaknesses in the maintainability and the design ofscreen. Those particular bugs were fixed, but I want to be fully transparent about the state ofscreen. I continue to use it, but it is further motivation to switch totmuxand you should heavily consider it yourself. While this post will talk aboutscreen, the concepts should be easily transferable totmux, assuming it doesn’t already have better support for my use case than I thought.
While I was happy with my choice, there were a couple of problems that made interacting
with instances of screen, or “screen sessions”, a bit of a pain:
screen starts with a full screen message that requires interaction to proceed to the
created session.screen
process and which pseudo terminal number (see man 7 pty) the kernel has
associated with your terminal. This scheme makes it easy to create a uniquely named
session, but less fun for a human to disambiguate or remember sessions.screen session is a manual process that I had to remember every time I
started a shell in order to reap the benefits of the aforementioned terminal crash
situation.GNU Screen version 4.09.01 (GNU) 20-Aug-23
Copyright (c) 2018-2023 Alexander Naumov, Amadeusz Slawinski
Copyright (c) 2015-2017 Juergen Weigert, Alexander Naumov, Amadeusz Slawinski
Copyright (c) 2010-2014 Juergen Weigert, Sadrul Habib Chowdhury
Copyright (c) 2008-2009 Juergen Weigert, Michael Schroeder, Micah Cowan,
Sadrul Habib Chowdhury
Copyright (c) 1993-2007 Juergen Weigert, Michael Schroeder
Copyright (c) 1987 Oliver Laumann
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program (see the file COPYING); if not, see
[Press Space for next page; Return to end.]
The copyright text `screen` presents on start-up.
To resolve these issues, I started calling into screen through a wrapper called ss,
two short letters to quickly launch a session whenever I started a new terminal session.
That name lasted about a day until I needed to call the very useful socket inspection
tool ss. So, I switched the name to sa, which is luckily also so very slightly
quicker to type.
The first iteration of sssa was very simple:
sa() {
screen -qR "$@"
}
# Fun fact: This would accomplish the same thing:
# alias sa="screen -qR"
# And if both were set, the alias would win.
It simply called screen, telling it to not launch that full screen window (-q) and
join the screen session specified after -R, creating one if none existed. The "$@"
just passes any arguments I passed to sa on to the screen invocation so I could give
sessions a name and pass any other arguments if I wanted to (I didn’t).
With this I had solved the full screen message problem and done a pretty good job of
solving the per-shell initialization problem with a simple to type wrapper I could
invoke on each launch. From there, it grew rather rapidly. I added -x to the
invocation so I could attach to the same screen session in multiple shells, and added
another -R so that I only had to pass part of an existing session’s name to rejoin it.
The real game changer was initializing it with human readable names without me passing
anything. Most Linux distributions come with a list of words in various languages in the
folder /usr/share/dict. My strategy sourced two random words from one of them and use
that as the human readable name if one wasn’t provided. With over 4 billion possible
combinations, I figured the chances of a collision were low enough to not care write
code actively prevent them.
sa() {
sessionName="$(grep -E '^[a-z]+$' /usr/share/dict/american-english \
| shuf -n 2 \
| tr '\n' '_' \
| sed -Ee 's/_$//'
)"
screen -xqRR "${@:-sessionName}"
}
The above code uses bash’s parameter expansion (
${<parameter>:-<default if not provided>}) to only pass that randomly generated
sessionName to screen if arguments aren’t passed to sa. The sessionName
calculation uses grep to grab only lower-cased words without extra symbols
from the dictionary. That list is passed into shuf which selects two entries
at random from it. Then tr replaces the new lines between the two selected words
with an underscore. Finally, sed removes the trailing underscore because the
output of shuf ends in a new line (which was turned into an underscore) and I didn’t
want that in the final name.
And so you get fun and memorable names like:
energies_oversightpigeon_guffawrattles_pharmacyAnd if you don’t like them, you can always pass your own, or update you current
session’s name with Ctrl+A :sessionname <your session name>. This nonsense solved my
human recollection problem.
And things have only grown from there. The latest version of the tool has so many other features, like:
sa session names associated with each shell instance. If you call sa,
detach from the created screen session, then call sa again, your back in that
initial session.sa sessions on remote machines reachable via SSH.sa-peek that lets you look at what a screen session currently
contains without actually attaching to it.sa session by invoking
_sa_auto in your shell’s rcfile (e.g., .bashrc), so you don’t even have to
remember to invoke sa.All of this, and a bit more can be found over on sa’s tool page. If you
run into any bugs, the man pages have but report contact information but don’t
hesitate to get your hands dirty and shape it to your own needs.
That initial, simple screen wrapper created the entry point from which grew so much
custom tooling to greatly streamline the way I interact with the command line and the
utilities I invoke in it.
As I opened with, I love the flexibility of the Linux command line. Wrappers are a great
example of that: your default interface into a tool need not be what the original
developer intended. I encourage you to take a look at the tools you use on a daily basis
to find ways you can make them that much faster. (I personally even wrap git itself.)
Even if you don’t get back the time you spend customizing the tool on your future uses
of it, I promise you the custom ergonomics are their own reward.
Till next time, cheers!
(And if you’ve been following my blog, I haven’t forgotten my promise to deliver my
netcat wrappers.)
Update September 20, 2026: I noticed a grammatical error in the
screenCVE notice that I fixed.