Better Titles in GNU Screen
I have been using this trick for years, but I never bothered documenting it. GNU Screen is one of those programs that does not seem like anything special when you first hear about it, and then becomes invaluable once you start using it. I use it to keep large number of terminal sessions open on a host -- some of them sessions parked in different folders, and some running different utilities.
But GNU Screen has a huge problem: the default screen titles are
useless. On a default Debian installation, when I hit <ctrl>+a "
to
see the list of windows I have opened, I see:
0 bash $
1 bash $
which does not help me keep track of my windows at all. It is possible
to set a title manually using <ctrl>+a A
, but this is irritating. I
want screen
to display titles automatically for me. Below are some
tricks to make those titles more dynamic and more useful. Upon running
certain commands I want to set the title to the command name;
otherwise I want to display the current directory.
Set current directory in .bashrc
Add the following snippet to your .bashrc
, somewhere after the PS
prompt setting:
# Set the screen title
case $TERM in
screen*)
# This is the escape sequence ESC k ESC \
SCREENTITLE='\[\ek\w\e\\\]'
;;
*)
SCREENTITLE=''
;;
esac
PS1="${SCREENTITLE}${PS1}"
The \w
sets the current working folder. The rest of the SCREENTITLE
line is a magic escape sequence that somehow sets the title for
the screen.
Set titles for the root user
I often find myself using sudo -s
to get root shells. I want those
shells to be distinct from the usual shells. To accomplish this, I put
the following stanza in the .bashrc
for root:
# Set the screen title
case $TERM in
screen*)
# This is the escape sequence ESC k ESC \
SCREENTITLE='\[\ekroot: \w\e\\\]'
;;
*)
SCREENTITLE=''
;;
esac
# I don't actually have this line in root's .bashrc, because
# I use the prompt below instead
PS1="${SCREENTITLE}${PS1}"
This adds the static text root:
before the prompt.
Make root prompt red
This is not directly related to GNU Screen, but I find it helpful to
confirm that I am using a root shell and not a regular one. Add
the following snippet to the .bashrc
for root:
RED='\[\033[0;31m\]'
NOCOLOR='\[\033[0m\]'
export PS1="${SCREENTITLE}${RED}${PS1}${NOCOLOR}"
Now the root prompt will be red. These are more magical escape sequences I don't pretend to understand, but I do know that you can use other colours if you want.
Set title to program names
I could not find a systematic way of doing this, but I have an ad-hoc
method that works well enough. For programs I use regularly and leave
running for a long time (such as w3m
,
newsbeuter
, mutt
, vim
, or top
) I have a small shell scripts
that performs a benevolent Man-in-the-Middle attack: it intercepts the
calls to these programs, sets the screen title, and then calls the
actual executable. Here is the script, called runwithtitle.sh
:
#!/bin/sh
cmd=`basename $0`
#set the screen title
case $TERM in
screen*)
# Escape all whitespace chars (\s : whitespace)
titletext=`echo "$cmd $@" | sed -e 's/\s/\\ /g'`
/usr/bin/screen -X title "$titletext"
;;
esac
/usr/bin/$cmd $@
The basename $0
identifies the name of this command. Then the case
statement sets the title. Finally, the command name is run, assuming
it lives in /usr/bin
.
To use this script, I make a symlink to the script with the name of the command I wish to track:
cd ~/bin
ln -s runwithtitle.sh vim
ln -s runwithtitle.sh newsbeuter
Now when I run vim
the local copy of the command (in ~/bin/vim
) is
called.
I have to use different versions of this script sometimes.
If the command takes arguments then I copy the runwithtitle.sh
script and change the last line to call the command explicitly. One
example of this is chromium
, which I always want to run with the
--incognito
switch. Another example is my quick shortcut d
, which
I use to conduct searches on DuckDuckGo:
#!/bin/bash
# Wow this is fragile. I had better not have any tabs
# in the query.
# putting double-quotes around phrases I want to keep does not
# work unless I single-quote expressions. This is because
# of how Bash parses arguments
changedargs=`echo $@ | sed -e "s/ /+/g"`
newtitleargs=`echo $@ | sed -e "s/ /\\ /g"`
escquotes=`echo $newtitleargs | sed -e 's/"/%22/g'`
#set the screen title
case $TERM in
screen*)
/usr/bin/screen -X title "s $newtitleargs"
;;
esac
/usr/bin/w3m "https://duckduckgo.com/?q=$changedargs"
I also have to be careful because sometimes commands call other
commands. For example, w3m
uses sensible-editor
to edit
textfields, which calls vim
, which changes the titles (somewhat
unhelpfully). So I hardcode /usr/bin/vim
as the editor in the w3m
options screen instead of trying to fix sensible-editor
.
Startup windows
Often, I want a set of screens to start in certain situations. For
example, I have a set of screens that I use for taking notes, and one
I use when I am at work. To accomplish this I use screenrc
files.
For example, when listening to talks I use the following screenrc
:
# Allow copy/paste in Vim?
register [ "\033:se paste\015a"
register ] "\033:se nopaste\015a"
# Startup!
chdir /home/pnijjar/personal/talks
screen -t "talks" /usr/bin/hnb talks.hnb
screen -t "extranotes" /usr/bin/hnb extranotes.hnb
chdir
screen 2
select 0
This creates three windows, and selects the first one for use so that
I can take notes. Then, I make a ~/bin/talkscreen
command to use
this screenrc
:
#!/bin/bash
/usr/bin/screen -c ~/.talkscreenrc
Similarly, I can make a different screenrc
for work, and then have
another small command (workscreen
) that calls that screenrc
.