This week, Peter through some tips and tricks for upping your terminal game. Find out how to quickly search through your command history, make a fancy, colourful prompt, and some magic shortcut keys you definitely didn’t know about!
You can find the original slides for this talk here.
Outline
- Escape codes
- Customising the prompt
- The command line and readline
- History
- Command, process and variable substitutions
- Aliases and functions
Terminals are old

https://commons.wikimedia.org/wiki/File:GiraffaRecurrEn.svg

https://commons.wikimedia.org/wiki/File:Teletype.jpg
Fancier terminals
- konsole
- terminology
- terminator
- guake
- tilda
- rxvt-unicode
- xterm
- cool-retro-term
Escape codes
- Also known as control characters
- “In-band signalling”
- Terminal would intercept these and do something else instead of printing them
- Cover things like backspace, ringing the bell, newline, etc.
- Also allowed setting text attributes: bold, underscore, different colours
- Because they aren’t designed for printing, they might be hard to
type, or look a bit odd. Many include the
ESCcharacter (hence the name):
\033[030m ^[[30m
ESC [ 3 0 m \e[30m
- ”
^[” is the code forC-[, which is alsoESCor\e(0x1b, 033 in octal) - Actually many different types of terminals, that support different
control character sets. We’re normally interested in
“xterm-256color” and “ANSI” escape sequences
- Look under
/usr/share/terminfofor a few other examples…
- Look under
Using colours
- Set foreground colour with “
\033[03<0-8>m”, and reset with “\033[039m” - Set background colour with “
\033[04<0-8>m”, and reset with “\033[049m” - Normally just put all the colours into variables and reference them:
WARN_COLOUR="\033[031m"
RESET_COLOUR="\033[039m"
echo -e "${WARN_COLOUR}WARNING: badness${RESET_COLOUR}"
- Can use these colours in anything that writes to terminal (even Fortran!)
character(len=*), parameter :: red = char(27) // "[031m"
character(len=*), parameter :: reset = char(27) // "[039m"
print*, red // "WARNING: badness" // reset
Customising the prompt




PS1
- Default value is
\s-\v\$ - Lots of options:
info bash -n Controllingto see full list [\t] \u@\h \w:turns into[15:27:30] user@hostname ~/directory:- To use colours, we need to surround them with an additional
\[and\] - This lets bash know that they won’t take any space up on screen
PROMPT_COMMAND
- This is a command that is run every time before displaying the prompt
- You can use this to show you information about e.g the git repo you are in, or the number of jobs you have running on a supercomputer
Movement on the command line
readlineis the secret hero here- Readline provides many, many commands for moving about on the command line
info readlineto find out more- Follow the basic Emacs commands
C-means “Ctrl”,M-means “Alt” (used to be “Meta”)C-a/C-e: move to beginning/end of lineM-f/M-b: move forward/backward by a wordShift-PgUp/Shift-PgDown: scroll backwards/forwards
GNOME is annoying
- In GNOME, the default terminal grabs the Alt key
- Turn this off: Edit > Keyboard Shortcuts…, uncheck “Enable menu access keys”
Editing commands
M-dto delete the following wordC-kto delete from the cursor to the end of the lineC-uto delete from the cursor to the beginning of the line- Also works in lots of other places in Linux!
M-#to comment out a line- Fix a mistake on the previous line by running
^a^b^to replace the first instance of “a” with “b” and then rerun the command- Also useful for rerunning a command with a different parameter
- If a command is becoming long and hard to edit, you can open it in
your
$EDITORwithC-x C-e- For Emacs, the best thing to do is set
$EDITORtoemacsclientandM-x start-serverin Emacs – this will then cause things to pop-up in your existing Emacs session
- For Emacs, the best thing to do is set
Magic of readline
Quick aside
- You can use readline in your own programs
- You can even use readline to wrap other programs that don’t support
it out of the box –
rlwraphttps://github.com/hanslub42/rlwrap - For python projects, also check out
prompt-toolkithttps://github.com/jonathanslenders/python-prompt-toolkit
Movement through history
- Search with
C-r - You can also enable a fancier search. Put the following in your
~/.inputrc:
"\e[A": history-search-backward
"\e[B": history-search-forward
- Reload your inputrc with
C-x C-r - Now you can start typing a previous command and then use the cursor keys to browse all commands that start with those letters:
./ma...
./magic
./magical
Working out keycodes
Quick aside
- Quickest way to work out what keycode to put is to run
sed -n lthen hit the key and press enter:
sed -n l
^[[A
History expansion
- Special variables for referring to previous commands, all start with
“
!”- This is why you might struggle to use “
!” in commands/strings
- This is why you might struggle to use “
!!: Repeat the previous command!N: Refer to command on line N!-N: Refer to the command N lines back!foo: Refer to the last command starting with “foo”!$: Use the value of the last argument from the previous command- You can also insert the last argument from the previous command with
M-.- Except on Macs, where you need to do
ESC-., or change howoptionworks - You can also prefix with a number:
M-2 M-.to get the second argument (with zero being the previous command)
- Except on Macs, where you need to do
Keeping history
The problem with multiple terminals
- If you use multiple terminals, their histories get out of sync
- By default, only the history from last one open is kept!
- Easy fix: append to the history file on every command:
shopt -s histappend
PROMPT_COMMAND="history -a"
HISTFILESIZE=1000000000
HISTSIZE=1000000
- Last two commands just make sure we keep a lot of history…
Tab completion
- Hit
TABto auto-complete commands and filenames - maybe you’re lazy like me, and don’t care about capitalisations in
filenames, etc. Put the following in your
~/.inputrc:
set completion-ignore-case On
TAB: complete
"\e[Z": menu-complete
- Super useful when traversing the filesystem!
Command substitution
- Use the output of one command in another one:
$(command)- You can also use backticks, but
$()is better
- You can also use backticks, but
- Nest them!
echo $(ls $(echo foo))
Actually useful example
which pip
less $(!!)
- Find out where a command is installed (is it a system package, or something I’ve installed myself?)
- Assuming I think it’s a script, have a look at its contents
Process substitution
Another way of joining programs together
- How to compare the output of running two different programs?
- Could just dump the output of each program into separate files and
then
diffthem- This is boring
- Better way is “process substitution”:
diff <(command1) <(command2)
diff <(command1 | sort | uniq) <(command2 | sort | uniq)
diff <(ssh archer 'cat remote/file') local_file
- Connects the output of the “inner” commands with the input argument of the “outer” command
Variable substitution
- Bash has some fancy uses for curly braces:
- Drop the extension from a filename:
${foo%.*} - Or replace it with a different one:
${foo/tex/pdf} - Get the length of a string:
${#foo} - Read more: http://wiki.bash-hackers.org/syntax/pe
Curly brace expansion
- Quick way to iterate over a few options:
{a,b,c}givesa b c a{b,c}dgivesabd acd- Useful for installing multiple packages:
sudo apt install {lapack,hdf5}-dev- will install both the lapack and hdf5 development packages
- Copying one file to another:
cp filename{,.bak}
- Also does ranges:
{1..10}gives numbers 1 to 10,{a..z}gives…
Aliases
- Aliases are “another name” for a command
- Useful if you always run a command with the same options
ls family
alias ls='ls -hF --color' # add colors for filetype recognition
alias la='ls -Alh' # show hidden files
alias lt='ls -ltrh' # sort by date, most recent last
Functions
- Use functions for more complicated expressions
- If you find yourself writing particularly complicated bash, stop! Use a better language instead!
Useful example
function latest() {
# Print the most recent file in a given directory
lastfile=$(ls -tc --color=tty "$@" | head -1);
echo "$@$lastfile";
}
# Move the last file I downloaded here
mv -v "$(latest ~/Downloads)" .
Find idioms
Different ways of grepping files from find
find path/ -type f -exec grep foo {} \;
find path/ -type f | xargs grep foo
for f in $(find path/ -type f); do grep foo $f; done
Different shells
- ksh if you want more POSIX
- zsh if you want to be like Ed
- fish if you want to really stand out
- tcsh if you want to die inside
- xonsh if you really, really like python