bash readline emacs editing mode default keyboard shortcut cheat sheetLet me teach you how to work efficiently with command line history in bash.

This tutorial comes with a downloadable cheat sheet that summarizes (and expands on) topics covered in this guide.

Download PDF cheat sheet: bash history cheat sheet (.pdf) (downloaded: 234445 times)
Download ASCII cheat sheet: bash history cheat sheet (.txt) (downloaded: 25241 times)
Download TEX cheat sheet: bash history cheat sheet (.tex) (downloaded: 13185 times)

In case you are a first time reader, this is the 3rd part of the article series on working efficiently in bourne again shell. Previously I have written on how to work efficiently in vi and emacs command editing modes by using predefined keyboard shortcuts (both articles come with cheat sheets of predefined shortcuts).

First, lets review some basic keyboard shortcuts for navigating around previously typed commands.

As you remember, bash offers two modes for command editing - emacs mode and vi mode. In each of these editing modes the shortcuts for retrieving history are different.

Suppose you had executed the following commands:

$ echo foo bar baz
$ iptables -L -n -v -t nat
$ ... lots and lots more commands
$ echo foo foo foo
$ perl -wle 'print q/hello world/'
$ awk -F: '{print$1}' /etc/passwd

and you wanted to execute the last command (awk -F ...).

You could certainly hit the up arrow and live happily along, but do you really want to move your hand that far away?

If you are in emacs mode just try CTRL-p which fetches the previous command from history list (CTRL-n for the next command).

In vi mode try CTRL-[ (or ESC) (to switch to command mode) and 'h' ('j' for the next command).

There is another, equally quick, way to do that by using bash's history expansion mechanism - event designators. Typing '!!' will execute the previous command (more about event designators later).

Now, suppose that you wanted to execute 'iptables -L -n -v -t nat' command again without retyping it.

A naive user would, again, just keep hitting up-arrow key until he/she finds the command. But that's not the way hackers work. Hackers love to work quickly and efficiently. Forget about arrow keys and page-up, page-down, home and end keys. They are completely useless and, as I said, they are too far off from the main part of the keyboard anyway.

In emacs mode try CTRL-r and type a few first letters of 'iptables', like 'ipt'. That will display the last iptables command you executed. In case you had more than one iptables commands executed in between, hitting CTRL-r again will display older entries. In case you miss the right command and move too deep into history list, you can reverse the search direction by hitting CTRL-s (don't forget that by default CTRL-s stops the output to the terminal and you'll get an effect of "frozen" terminal (hit CTRL-q to "unfreeze"), see stty command to change this behavior).

In vi mode the same CTRL-r and CTRL-s still work but there is another way more specific to vi mode.
Switch to command mode by hitting CTRL-[ or ESC and hit '/', then type a first few characters of 'iptables' command, like 'ipt' and hit return. Bash will display the most recent match found in history. To navigate around use 'n' or just plain '/' to repeat the search in the same direction, and 'N' or '?' to repeat the search in opposite direction!

With event designators you may execute only the most recently executed command matching (or starting with) 'string'.

Try '!iptables' history expansion command which refers to the most recent command starting with 'iptables'.

Another way is to use bash's built in 'history' command then grep for a string of interest and finally use an event designator in form '!N', where N is an integer which refers to N-th command in command history list.

For example,

$ history | grep 'ipt'
  2    iptables -L -n -v -t nat
$ !2     # will execute the iptables command

I remembered another way to execute N-th command in history list in vi editing mode. Type 'N' (command number) and then 'G', in this example '2G'

Listing and Erasing Command History

Bash provides a built-in command 'history' for viewing and erasing command history.

Suppose that we are still working with the same example:

$ echo foo bar baz
$ iptables -L -n -v -t nat
$ ... lots and lots more commands
$ echo foo foo foo
$ perl -wle 'print q/hello world/'
$ awk -F: '{print$1}' /etc/passwd

Typing 'history' will display all the commands in bash history alongside with line numbers:

  1    echo foo bar baz
  2    iptables -L -n -v -t nat
  ...  lots and lots more commands
  568  echo foo foo foo
  569  perl -wle 'print q/hello world/'
  570  awk -F: '{print$1}' /etc/passwd

Typing 'history N', where N is an integer, will display the last N commands in the history.
For example, 'history 3' will display:

  568  echo foo foo foo
  569  perl -wle 'print q/hello world/'
  570  awk -F: '{print$1}' /etc/passwd

history -c will clear the history list and history -d N will delete a history entry N.

By default, the history list is kept in user's home directory in a file '.bash_history'.

History Expansion

History expansion is done via so-called event designators and word designators. Event designators can be used to recall previously executed commands (events) and word designators can be used to extract command line arguments from the events. Optionally, various modifiers can be applied to the extracted arguments.

Event designators are special commands that begin with a '!' (there is also one that begins with a '^'), they may follow a word designator and one or more modifiers. Event designators, word designators and modifiers are separated by a colon ':'.

Event Designators

Lets look at a couple of examples to see how the event designators work.

Event designator '!!' can be used to refer to the previous command, for example,

$ echo foo bar baz
foo bar baz
$ !!
foo bar baz

Here the '!!' executed the previous 'echo foo bar baz' command.

Event designator '!N' can be used to refer to the N-th command.
Suppose you listed the history and got the following output:

  1    echo foo foo foo
  2    iptables -L -n -v -t nat
  ...  lots and lots more commands
  568  echo bar bar bar
  569  perl -wle 'print q/hello world/'
  570  awk -F: '{print$1}' /etc/passwd

Then the event designator '!569' will execute 'perl ...' command, and '!1' will execute 'echo foo foo foo' command!

Event designator '!-N' refers to current command line minus N. For example,

$ echo foo bar baz
foo bar baz
$ echo a b c d e
a b c d e
$ !-2
foo bar baz

Here the event designator '!-2' executed a one before the previous command, or current command line minus 2.

Event designator '!string' refers to the most recent command starting with 'string'. For example,

$ awk --help
$ perl --help

Then the event designator '!p' or '!perl' or '!per' will execute the 'perl --help' command. Similarly, '!a' will execute the awk command.

An event designator '!?string?' refers to a command line containing (not necessarily starting with) 'string'.

Perhaps the most interesting event designator is the one in form '^string1^string2^' which takes the last command, replaces string1 with string2 and executes it. For example,

$ ehco foo bar baz
bash: ehco: command not found
$ ^ehco^echo^
foo bar baz

Here the '^ehco^echo^' designator replaced the incorrectly typed 'ehco' command with the correct 'echo' command and executed it.

Word Designators and Modifiers

Word designators follow event designators separated by a colon. They are used to refer to some or all of the parameters on the command referenced by event designator.

For example,

$ echo a b c d e
a b c d e
$ echo !!:2

This is the simplest form of a word designator. ':2' refers to the 2nd argument of the command (3rd word). In general ':N' refers to Nth argument of the command ((N+1)-th word).

Word designators also accept ranges, for example,

$ echo a b c d e
a b c d e
$ echo !!:3-4
c d

There are various shortcuts, such as, ':$' to refer to the last argument, ':^' to refer to the first argument, ':*' to refer to all the arguments (synonym to ':1-$'), and others. See the cheat sheet for a complete list.

Modifiers can be used to modify the behavior of a word designators. For example:

$ tar -xvzf software-1.0.tgz
$ cd !!:$:r

Here the 'r' modifier was applied to a word designator which picked the last argument from the previous command line. The 'r' modifier removed the trailing suffix '.tgz'.

The 'h' modifier removes the trailing pathname component, leaving the head:

$ echo /usr/local/apache
$ echo !!:$:h

The 'e' modifier removes all but the trailing suffix:

$ ls -la /usr/src/software-4.2.messy-Extension
$ echo /usr/src/*!!:$:e
/usr/src/*.messy-Extension    # ls could have been used instead of echo

Another interesting modifier is the substitute ':s/old/new/' modifier which substitutes new for old. It can be used in conjunction with 'g' modifier to do global substitution. For example,

$ ls /urs/local/software-4.2 /urs/local/software-4.3
/usr/bin/ls: /urs/local/software-4.2: No such file or directory
/usr/bin/ls: /urs/local/software-4.3: No such file or directory
$ !!:gs/urs/usr/

This example replaces all occurances of 'urs' to 'usr' and makes the command correct.

There are a few other modifiers, such as 'p' modifier which prints the resulting command after history expansion but does not execute it. See the cheat sheet for all of the modifiers.

Modifying History Behavior

Bash allows you to modify which commands get stored in the history list, the file where they get stored, the number of commands that get stored, and a few other options.

These options are controlled by setting HISTFILE, HISTFILESIZE, HISTIGNORE and HISTSIZE environment variables.

HISTFILE, as the name suggests, controls where the history file gets saved.
For example,

$ export HISTFILE=/home/pkrumins/todays_history

will save the commands to a file /home/pkrumins/todays_history

Set it to /dev/null or unset it to avoid getting your history list saved.

HISTFILESIZE controls how many history commands to keep in HISTFILE.
For example,

$ export HISTFILESIZE=1000

will keep the last 1000 history commands.

HISTSIZE controls how many history commands to keep in the history list of current session.
For example,

$ export HISTSIZE=42

will keep 42 last commands in the history of current session.

If this number is less than HISTFILESIZE, only that many commands will get written to HISTFILE.

HISTIGNORE controls the items which get ignored and do not get saved. This variable takes a list of colon separated patterns. Pattern '&' (ampersand) is special in a sense that it matches the previous history command.

There is a trick to make history ignore the commands which begin with a space. The pattern for that is "[ ]*"

For example,

$ export HISTIGNORE="&:[ ]*:exit"

will make bash ignore duplicate commands, commands that begin with a space, and the 'exit' command.

There are several other options of interest controlled by the built-in 'shopt' command.

The options may be set by specifying '-s' parameter to the 'shopt' command, and may be unset by specifying '-u' parameter.

Option 'histappend' controls how the history list gets written to HISTFILE, setting the option will append history list of current session to HISTFILE, unsetting it (default) will make HISTFILE get overwritten each time.

For example, to set this option, type:

$ shopt -s histappend

And to unset it, type:

$ shopt -u histappend

Option 'histreedit' allows users to re-edit a failed history substitution.

For example, suppose you had typed:

$ echo foo bar baz

and wanted to substitute 'baz' for 'test' with the ^baz^test^ event designator , but you made a mistake and typed ^boo^test^. This would lead to a substitution failure because the previous command does not contain string 'boo'.

If you had this option turned on, bash would put the erroneous ^baz^test^ event designator back on the command line as if you had typed it again.

Finally, option 'histverify' allows users to verify a substituted history expansion.

Based on the previous example, suppose you wanted to execute that 'echo' command again by using the '!!' event designator. If you had this option on, bash would not execute the 'echo' command immediately but would first put it on command line so that you could see if it had made the correct substitution.

Tuning the Command Prompt

Here is how my command prompt looks:

Wed Jan 30@07:07:03

The first line displays the date and time the command prompt was displayed so I could keep track of commands back in time.
The second line displays username, hostname, global history number and current command number.

The global history number allows me to quickly use event designators.

My PS1, primary prompt display variable looks like this:

PS1='\d@\t\n\u@\h:\!:\#:\w$ '

Bash History Cheat Sheet

Here is a summary cheat sheet for working effectively with bash history.

This cheat sheet includes:

  • History editing keyboard shortcuts (emacs and vi mode),
  • History expansion summary - event designators, word designators and modifiers,
  • Shell variables and `shopt' options to modify history behavior,
  • Examples

Download Bash History Summary Sheet

PDF format (.pdf):
Download link: bash history cheat sheet (.pdf)
Downloaded: 234445 times

ASCII .txt format:
Download link: bash history cheat sheet (.txt)
Downloaded: 25241 times

LaTeX format (.tex):
Download link: bash history cheat sheet (.tex)
Downloaded: 13185 times

This cheat sheet is released under GNU Free Document License.

Are there any tips you want to add?

bash readline vi editing mode default keyboard shortcut cheat sheet Bash provides two modes for command line editing - emacs and vi. Emacs editing mode is the default and I already wrote an article and created a cheat sheet for this mode.

This time I am going to introduce you to bash's vi editing mode and give out a detailed cheat sheet with the default keyboard mappings for this mode.

The difference between the two modes is what command each key combination (or key) gets bound to. You may inspect your current keyboard mappings with bash's built in bind command:

$ bind -P

abort can be found on "\C-g", "\C-x\C-g", "\M-\C-g".
accept-line can be found on "\C-j", "\C-m".
alias-expand-line is not bound to any keys

To get into the vi editing mode type

$ set -o vi

in your bash shell (to switch back to emacs editing mode, type set -o emacs).

If you are used to a vi text editor you will feel yourself at home.

The editing happens in two modes - command mode and insert mode. In insert mode everything you type gets output to the terminal, but in the command mode the keys are used for various commands.

Here are a few examples with screenshots to illustrate the vi editing mode.

Let '[i]' be the position of cursor in insert mode in all the examples and '[c]' be the position of cursor in command mode.


Once you have changed the readline editing mode to vi (by typing set -o vi), you will be working in insert mode.

The example will be performed on this command:

$ echo arg1 arg2 arg3 arg4[i]

Example 1:

Suppose you have typed a command with a few arguments and want to insert another argument before an argument which is three words backward.

$ echo arg1 (want to insert arg5 here) arg2 arg3 arg4[i]

Hit 'ESC' to switch to command mode and press '3' followed by 'B':

$ echo arg1 [c]arg2 arg3 arg4

Alternatively you could have hit 'B' three times: 'BBB'.

Now, enter insert mode by hitting 'i' and type 'arg5 '

$ echo arg1 arg5 [i]arg2 arg3 arg4

Example 2:

Suppose you wanted to change arg2 to arg5:

$ echo arg1 [c]arg2 arg3 arg4

To do this, you can type 'cw' which means 'change word' and just type out 'arg5':

$ echo arg1 arg5[c] arg3 arg4

Or even quicker, you can type 'f2r5', where 'f2' moves the cursor right to next occurrence of character '2' and 'r5' replaces the character under the cursor with character '5'.

Example 3:

Suppose you typed a longer command and you noticed that you had made several mistakes, and wanted to do the correction in the vi editor itself. You can type 'v' to edit the command in the editor and not on the command line!

Example 4:

Suppose you typed a long command and remembered that you had to execute another one before it. No need to erase the current command! You can switch to command mode by hitting ESC and then type '#' which will send the current command as a comment in the command history. After you type the command you had forgotten, you may go two commands back in history by typing 'kk' (or '2k'), erase the '#' character which was appended as a comment and execute the command, this makes the whole command look like 'ESC 2k0x ENTER'.

These are really basic examples, and it doesn't get much more complex than this. You should check out the cheat sheet for other tips and examples, and try them out!

To create the cheat sheet, I downloaded bash-2.05b source code and scanned through lib/readline/vi_keymap.c source code file and lib/readline/vi_mode.c to find all the default key bindings.

It turned out that the commands documented in vi_keymap.c were all documented in man 3 readline and I didn't find anything new.

After that I checked bashline.c source file function initialize_readline to find how the default keyboard shortcuts were changed. I found that 'CTRL-e' (which switched from vi mode to emacs) got undefined, 'v' got defined which opens the existing command in the editor, and '@' which replaces a macro key (char) with the corresponding string.

The cheat sheet includes:

  • Commands for entering input mode,
  • Basic movement commands,
  • Character finding commands,
  • Character finding commands,
  • Deletion commands,
  • Undo, redo and copy/paste commands,
  • Commands for history manipulation,
  • Completion commands,
  • A few misc. commands, and
  • Tips and examples

Download Vi Editing Mode Cheat Sheet

PDF format (.pdf):
Download link: bash vi editing mode cheat sheet (.pdf)
Downloaded: 173446 times

ASCII .txt format:
Download link: bash vi editing mode cheat sheet (.txt)
Downloaded: 37506 times

LaTeX format (.tex):
Download link: bash vi editing mode cheat sheet (latex .tex)
Downloaded: 12388 times

This cheat sheet is released under GNU Free Document License.

I was doing a WordPress installation the other day when I noticed how insecure the default generated password was.

On line 38 in wp-admin/includes/upgrade.php (wordpress version 2.3.1) I found that a 6 character password is generated this way:

$random_password = substr(md5(uniqid(microtime())), 0, 6);

The md5 function returns a 32 character hexadecimal number and substr chops off first six characters. Doing elementary combinatorics we can find that the number of possible passwords is 166 (16 to the power 6) or 16,777,216, or roughly just 16.7 million passwords!

I am more than sure that most people doing WP installations never change the default password. If you're on a good connection and can do just 100 password checks per second, then you can crack a WordPress installation in worst case time of 16,777,216/100 seconds, which is 46.6 hours! Most likely you'd crack the password in half of that time, so you can crack any WordPress installation that has a default password in about 24 hours!

charles darvin - natural selectionI have started working on my bachelor's thesis in physics. It's about using genetic algorithms for finding optimal solutions to physics problems. One of the problems I will solving is simulating equilibrium configurations of two dimensional systems of particles which can attract and repel (dipole systems). This problem is NP hard, which means there is no effective algorithm to find the exact solution in an adequate time. Several other algorithms can be used to approximate the solution and find near-equilibrium configurations, one of them being genetic algorithm technique.

The easiest situation is when the particles are bounded in a circle which border they can't trespass. The goal is to find how these particles will position themselves inside this circle.

This case has already been tackled using the simulated annealing method and the near-optimum solutions for hundreds of particles have been found. This method uses different principles than genetic algorithm method which I will describe shortly. The main idea of simulated annealing method is that the system is given an initial temperature which basically controls how much the particles will fluctuate inside the system. The greater the temperature, the bigger the fluctuations. The temperature gradually gets decreased and the fluctuations get smaller and smaller. Calculating the energy of the system and requiring it to be minimal at each step the temperature gets decreased eventually leads to a solution.

Here is how the solutions for 10, 11, 12, 13, 14 and 15 particles looks like, found using simulated annealing algorithms:

dipole system

Notice how interestingly and non-intuitively the particles position themselves in a case when another particle gets added to a system of 12 particles. Instead of positioning the new particle somewhere in the middle as in transition from 11 particles to 12, the system decides to put it on the border.

In my thesis I will be using genetic algorithms to arrive at the solution for this problem.

Here is a general (not related to my topic of thesis) description of what genetic algorithms are.

Genetic Algorithms 101

Genetic algorithms mimic the evolution by natural selection. The basic idea of genetic algorithms is very simple. Genetic algorithms feature populations of individuals which evolve with the use of the principles of selection, variation and inheritance.

One of the ways to implement this idea in computer programs is to represent individuals as strings of binary digits. Each bit in the string represents one gene. Each individual is assigned a numerical evaluation of its merit by a fitness function. The fitness function determines how each gene of an individual will be interpreted and, thus, what specific problem the population will evolve to solve.

Once all individuals in the population have been evaluated, their fitness values are used for selection. Individuals with low fitness get eliminated and the strongest get selected. Inheritance is implemented by making multiple copies of high-fitness individuals. The high-fitness individuals get mutated and they crossover to produce a new population of individuals. Mutation is implemented as flipping individual bits in the binary string representation of an individual and crossover happens as an exchange of binary substrings of two individuals to obtain a new offspring.

By transforming the previous set of individuals to a new one, the algorithm generates a new set of individuals that have better fitness than the previous set of individuals. When the transformations are applied over and over again, the individuals in the population tend to represent improved solutions to whatever problem was posed in the fitness function.

Here is an illustration how a genetic algorithm might work:

operation of the genetic algorithm programming

I look forward to finding what other interesting projects that I can make using the very useful information I have learnt.

PS. I am writing blog posts less often now because I am really, really busy with studies. Sorry about that.

bash readline emacs editing mode default keyboard shortcut cheat sheetWhen you are working in a shell you certainly don't want to waste your time using arrow keys or home/end keys to navigate around the command line. One of the most popular shells, bash - Bourne Again SHell, uses GNU's Readline library for reading the command line.

The GNU Readline library provides a set of functions for use by applications that allow users to edit command lines as they are typed in. The readline library also includes functions to maintain a list of previously-entered command lines, to recall and perhaps reedit those lines, and perform csh-like history expansion on previous commands. Both emacs and vi editing modes are available.

I have mastered both of the editing modes and have created cheat sheets for both of them (and a tiny separate one for readline's history expansion).

This is a cheat sheet for the default, emacs, editing mode.

Here are a few examples with screenshots on how to use this editing mode.

Let '[]' be the position of cursor in all the examples.

Example 1: movement basics

Suppose you are at the end of the line and want to move 3 words backwards.

$ echo word1 word2 word3 word4 word5 word6[]

If you hit M-3 followed by M-b, you would end up exactly where you wanted:

$ echo word1 word2 word3 []word4 word5 word6

An alternative is to hit M-b three times in a row: M-b M-b M-b

If you look up on the cheat sheet what M-3 does, it sets the numeric-argument to 3 which in this case acts as a counter how many times should M-b command be repeated. The M-b command calls backward-word function which does the obvious.

The numeric-argument can also be negative, which makes the argument to be applied in the opposite direction.

Other shortcuts of interest are M-f to move forward and C-a, and C-e to move to the beginning and end of line.

Example 2: command history

Suppose you used a pretty complex command a while ago and now you remember just a few arguments of this command. You want to find this command and call it with a few arguments modified.

If you hit C-r readline will put you in an incremental reverse history search mode. Typing a part of the arguments you remember, will locate the previously executed command matching the typed text. Hitting C-r again will locate any other command which matches your typed text.

To put the found command on command line for editing hit C-j.

Example 3: completing

Suppose you want to quickly list all the users on the system.

Hit C-x ~ and read-line will attempt username completion and output all the usernames to the terminal.

$ []
adm        catonmat   ftp        halt       mailnull   nobody     root       smmsp      vcsa
apache     cpanel     games      lp         mysql      nscd       rpc        sshd
bin        daemon     gopher     mail       named      operator   rpm        sync
cat        dbus       haldaemon  mailman    news       picurls    shutdown   uucp
$ []

Suppose you now want to quickly list all the users on the system starting with 'm'. You can type 'm' followed by the same C-x ~ to do that.

$ m[]
mail      mailman   mailnull  mysql
$ m[]

The other interesting completions are:

  • C-x / which lists possible filename completion,
  • C-x $ which lists possible bash variable completion,
  • C-x @ which lists possible hostname completion and,
  • C-x ! which lists possible command completion.


  • Meta-/ which does filename completion,
  • Meta-$ which does bash variable completion,
  • Meta-@ which does hostname completion and,
  • Meta-! which does command completion.

Example 3: killing and yanking

Suppose you have to type a-long-word-like-this a couple of times.

The easiest way to do this is to kill the word, which puts it into the kill ring. Contents of the kill ring can be accessed by yanking.

For example, type 'a-long-word-like-this' in the shell:

$ command a-long-word-like-this []

Now press C-w to kill one word backward:

$ command []

Press C-y to yank (paste) the word as many times as you wish (I pressed it 3 times here:)

$ command a-long-word-like-this a-long-word-like-this a-long-word-like-this []

The kill ring does not contain just the one latest killing. It can be filled with a number of kills and rotated with M-y shortcut.

Another example:

Suppose you typed a longer command and you noticed that part of the THE TEXT GOT TYPED IN CAPITAL LETTERS. Without knowing the readline shortcuts you would erase the text and probably type it again. Now you can use the readline keyboard shortcuts and change the case very, very quickly.

You can use the following shortcuts to accomplish this:

1) M-l (Meta-l (on your computer, probably ESC-l)) shortcut is bound to readline's downcase-word function which lowercases the current word.
2) M-b shortcut is bound to readline's backward-word function which moves the cursor one word backwards.
3) M-<number> shortcut is bound to readline's numeric-argument function which in some cases acts as how many times should the following command be repeated.

Here is a real word example, suppose we have typed the following ([] is the cursor):


To get to the beginning of 'THE' we might repetitively hit M-b seven times or we could set the numeric argument to seven by typing M-7 and then hit M-b once.

After doing this the cursor would have moved before the word 'THE':


Now, by setting the numerical argument to 7 again and by pressing M-l or by pressing M-l seven times, we turn the text all in lower case.

$ echo the text. the text got typed in capital letters[]

Actually what we did in this example was not as efficient as it could have been. The numeric-argument shortcut accepts negative arguments which turn the direction of the following command in other direction. We could have turned the text in lower case by hitting M--7 and M-l

If you really want to be more productive, I suggest you play around with the commands in the cheat sheet for a while.
My previous article on being more productive on the command line was screen's cheat sheet which allows to emulate multiple terminals in a single window. You can take a look at it as well!

Download Emacs Editing Mode Cheat Sheet

PDF format (.pdf):
Download link: readline emacs cheat sheet (.pdf)
Downloaded: 72455 times

ASCII .txt format:
Download link: readline emacs cheat sheet (.txt)
Downloaded: 16916 times

LaTeX format (.tex):
Download link: readline emacs cheat sheet (.tex)
Downloaded: 9119 times

This cheat sheet is released under GNU Free Document License.

The next cheat sheet will be readline's vi editing mode's default keyboard shortcut cheat sheet! :)