GNU screen is a useful tool, it has been mentioned in multiple earlier articles as a good way to keep a program running after you log out of a server.
Screen runs commands in sessions. Each session can have multiple screens in which commands are run, which can be a more useful interface to multiprocessing than running jobs in the background.
A screen session can be connected to by multiple terminals, and can be detached from entirely, so there's no user reading the command's output.
Creating a session
The simplest use of screen is to simply enter screen
at which point
it creates a new session, running your shell.
Commands other than the default of your shell can be executed too. You
can run screen tail -f /var/log/foo.log
to watch the logged output of
a command.
You can specify the name of the session with the -S
argument, which
can be used later to re-join or kill a session by name.
Entering commands
Screen has many default key-bindings for running commands. These are
mostly prefixed by the escape key. This defaults to ^A
(read as holding
Ctrl an pressing the a key).
^A
is commonly used by emacs users to move the cursor to the
beginning of the line. It is possible to re-bind to a different key by
putting escape $KEY
in your ~/.screenrc
.
escape ^Bb
will make screen use ^B
for its escape character, rather
than ^A
.
Commands that had not been bound can be entered by entering the ^A:
command (hold Ctrl, press a, then press :). This will open a command
line interpreter, where you can enter other commands.
Opening a new screen in your session
The screen
command will open a new screen in the same session. The
keyboard shortcut for this is to enter ^Ac
, which opens a new screen
and runs a shell in it.
To run a specific command in your new screen, just like how we create the initial screen session, just in the screen command line, rather than your shell's command line.
For example, entering screen tail -f /var/log/foo.log
in the command
line opened by pressing ^A:
, will open a new screen and read the output
of foo.log
into it, which can be used to monitor the logs of a command
being run in another screen.
Switching screens
^Aa
will switch between your current screen and your previous screen.
Your open screens are listed in the caption at the bottom of the
screen. Pressing ^A$NUMBER
will switch to that screen, so ^A1
will
switch to the first screen.
^A"
will open a menu of screens to switch to, including what command
is running in that screen, which is useful if the information in the
caption bar isn't sufficient.
The command to switch screens is called select
, so running select 1
in screen's command line will switch to screen 1.
Splitting screens
Using screen to manage multiple commands is already an improvement over bash's job control.
- The caption bar shows you which commands are running
- You don't need to background a command to have multiple running
- The output from multiple commands doesn't get interleaved into an incomprehensible mess, since the output is separated by screen.
However, we currently can only see the output of one command at a time, so we can't use our earlier example of looking at the logged output of the foo command, while running other commands.
To handle this, screen allows you to split your view into multiple
windows.. ^As
produces a horizontal split, so you can have one window
at the top, and a different below it.
^A|
creates a vertical split, so you can have a different window on
the left and the right.
Various windows can be cycled between with the ^A<TAB>
key.
^AX
will remove the current split, and ^AQ
will remove all windows
except the one which currently has focus.
Closing screens in your session
When the primary process of a screen terminates, the associated screen
will close, so if you enter exit
on your shell, the screen will close.
If a screen is stubbornly refusing to exit, you can run ^Ak
to kill
the current screen.
Closing a session
When all commands run in a screen session exit, the session is closed.
If a command is not easily closed or you do not care for cleanly closing
it, then you can press the ^A\
shortcut to kill everything, or entering
the quit
on the screen command line.
Detaching from a session
A screen session can be left running without any user being connected
to it. This can be accomplished by creating one as before, and pressing
^AD
to detach yourself from it.
A screen can be started in detached mode by starting it as screen -d -m
.
Joining an existing session
screen -x
will join an existing session, even if there is currently
a user already attached. This allow multiple users on the same screen
session, but can behave strangely if each user has a different terminal
size.
The latest session with no users can be re-attached to with screen
-R
. This can fail if the latest screen session has a user, so there's
the -d
option too, which will detach the session first if necessary.
The -D
command is useful, since you can also provide the command
you want to run as the first argument, so screen -D -R tail -f
/var/log/foo.log
will detach and re-attach to an existing session if
it exists, otherwise it will create a new one reading log output.
Use the history
command to see the whole command history of your
shell:
$ history
...
501 cd ../yakking.branchable.com/
502 ls posts
503 less posts/command-line-basics.mdwn
504 history
$
This shows the whole history. You can pipe it to less
or grep
or
other tools, as needed. You can, for example, count which command you
use most:
$ history | awk '{ print $2 }' | sort | uniq -c | sort -n | tail
15 emacs
15 man
15 ./ripit
18 rm
23 python
29 less
31 ssh
44 ls
52 cd
68 git
$
This isn't necessarily quite accurate, though. I use the Bash
HISTCONTROL=ignoredups
setting, which removes exact duplicates of
command lines from the history. Thus, while I run commands like
./check
and python setup.py check
very often, they don't show up
in the counts above.
screen is sometimes denounced for its bloat, usually by tmux proponents, but these features come in useful, and screen's wide availability makes it useful to learn these features.
Copying and pasting text
^A[
opens selection mode. This lets you scroll through your output and
select sections by pressing enter then moving your cursor to the end of
your selection and pressing enter again.
You can paste the selection by pressing ^A]
, which will input the
previously selected text, so you can save useful snippets of a command
by copying with ^A[
, opening a text editor, and pressing ^A]
to
paste it.
Customising your caption line
If you opened multiple screens in the same session, you will see a bar at the bottom listing which screens are open. This is called the caption bar.
If you want to always see it, you need to run the caption always
command.
You can either add it to your ~/.screenrc
file, for it to always
happen when you open a terminal, or invoke it directly on the screen
command line by pressing ^A:
to open the command line, then enter
caption always
and press enter to run the command.
Like your shell's prompt, the caption bar can be customised. This is
done by entering caption string $SPEC
.
There are many options possible, and referring to the screen(1) manpage is more useful than memorising them. The following example lists the number and title of all screens in the caption, and highlights the current screen in red:
caption string "%?%F%{.R.}%?%3n %t%? [%h]%?"
Screen config for complicated setups
Instead of specifying a command to run when you start your screen session, you can pass a path to a configuration file to run instead.
For example, you could put this in a config file for an irssi
session:
$ cat >irssi-screen-config <<EOF
screen -t irssi irssi
EOF
With this config you can then put the following command in an appropriate place to start services, and have your computer start an irssi session in a screen session on start-up.
$ screen -D -m irssi-screen-config
You can also use the hash-bang line of a file to turn your config file into a screen script.
$ cat >irssi-screen-config <<EOF
#!/usr/bin/screen -Dm
screen -t irssi irssi
EOF
Serial console client
It is common for high-end switches and development boards to have a serial port as a back-up control interface, so when everything else is failing there's still a way to diagnose, and potentially fix a problem.
When appropriate cables have been connected, your machine will typically
have added a /dev/ttyUSB0
device node to represent the connection.
Reading and writing to this device will send and recieve data along the serial port line. However, in typical embedded linux appliances the other side of the serial connection is a getty, or login console.
To communicate with this, you need a client application.
Given this article is about screen, it should come as no surprise for me to announce that screen can act as such a client.
Rather than doing screen $COMMAND
, to run a command in a local tty,
you run screen /dev/ttyUSB0 115200
.
See the "Window Types" section of screen(1) for details about what the 115200 option is, and when you would need to change it.
This is arguably a sign of bloat, that a program about terminal multiplexing includes a serial console client, however it's convenient, as screen is widely available on Linux distros.
Filter commands
Use ^A:
to open the screen command line. Enter exec COMMAND
to run
that command.
A sequence of !
, .
or :
symbols before the command can be used to
specify whether the input comes from your keyboard (the screen's input)
or the output of the command running in your screen.
Exactly which symbols to use is a bit of a mystery, but !!
replaces
your shell with another program talking to the terminal. For anything
else, see the screen(1) manpage.
Sending files with xmodem
xmodem is a protocol for file transfer over a serial connection.
It's old and fragile, but it's simple, so development boards sometimes have it as a fall-back for when everything else fails.
sx(1) is a tool to communicate over xmodem. It can also do the
ymodem protocol by invoking it as sx --ymodem
.
After opening the command line with ^A:
, enter exec !! sx $FILE
to send that file over xmodem.
xmodem isn't completely reliable, so it may be necessary to re-run the command.
What configuration do you have, and how much of it matters
On *NIX
based systems, there are a number of places that your configuration
might be found. Traditionally, system configuration can be found in /etc
in
a number of text files which are nominally human-readable and human-editable.
The equivalent of those files for your specific user are found in your home
directory, but rather than being conveniently kept in ~/etc
they are
typically kept directly in ~
but hidden from view. The *NIX
idiom of
hiding files from listings if they start with a full-stop (e.g. .xinitrc
)
means that your configuration files typically start with a full-stop and are
thus referred to as your dot-files.
If you want to see just how many of these things there are, try comparing the
output of ls ~
and ls -a ~
. For me, the difference is 180 entries. Not
every single one of those entries is a configuration file which I might care
about. For example ~/.cache
is simply where the applications you run store
their cache data; and ~/.cabal
is where your locally installed Haskell
applications and libraries live. Both of those contain data it might be
valuable to keep, but neither are very amenable to management outside of the
tools and programs which write to them.
I like to separate configuration into that which I feel I need to keep (and/or keep synchronised between systems) and that which I do not mind if I lose. For example, I would be lost without my personalised ZShell configuration but would not lose very much sleep at all over my libreoffice personalisations going missing. In some cases this separation can also be made based on whether or not I wrote the configuration file by hand. I don't tend to feel that software-managed configuration files are precious.
How can you keep your configuration safe
Having decided which of your configuration files are precious, there now comes the realisation that, just like your programming projects, you need to keep your precious configuration files safe. And, as we have said before, that means both tracking changes and keeping copies.
There are a number of ways of achieving this. Some people like to treat their entire home directory as a revision controlled space, explicitly choosing to add files or ignore them as and when they turn up. For example, Joey Hess likes to do this, or at least he did when he wrote that blog posting. Some people like to keep specific bits of their configuration in revision control, such as John Wiegley's Emacs config. Others, such as myself, choose to keep their "precious" dotfiles in revision control. I do this in my git repository and amazingly so do Richard Maw and Lars Wirzenius -- anyone would think we were all friends who talked about this stuff a lot.
In the past I, and no doubt others (who perhaps persist in doing so to this day), kept my precious files in a tarball and periodically refreshed the tarball and sent it to my various systems. But in 1999 when I got my first real job, I was suddenly plunged into a situation where I had to deal with around 6 different platforms, in varying operating systems, across around 15 different machines and that's what finally caused me to take the plunge and keep my dotfiles in revision control. Initially I used Perforce since that was what was available at my place of work, but then I moved via CVS, Subversion, TLA and Bazaar-NG before finally ending up where I am right now (in Git).
Whatever approach you take, keeping your precious dotfiles safe will give you a sense of security and "home" whenever you have a new system you need to get a foothold in.
Keeping your safe-keeping safe
In all the above, I've not mentioned one of my favourite things -- security. You will be tempted to commit config files which contain passwords. You will be tempted to commit secret keys. You might be tempted to commit configurations which happen to leak secret information about your employer such as customer names in your folder list in your email configuration. There are a number of approaches to this issue. One is simply not to publish your dotfile repository for others to see. Another is to keep a separate clone of the repository and merge changes from your open repository to your private repository when you need to (my chosen approach). Finally you might choose to make full use of the functionality of your revision control system and have your private repository use something like git submodules to bring in your public repository as and when it needs to.
Whatever approach you choose, please remember to keep your private data private at the same time as you keep your precious configuration safe.