bash readline emacs editing mode default keyboard shortcut cheat sheet

Let 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: 246775 times)
Download ASCII cheat sheet: bash history cheat sheet (.txt) (downloaded: 33188 times)
Download TEX cheat sheet: bash history cheat sheet (.tex) (downloaded: 21208 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: 246775 times

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

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

This cheat sheet is released under GNU Free Document License.

Are there any tips you want to add?


February 19, 2008, 04:09

Hi there, kak dela..
One more great article here, took me some time to implement but working just awesome as always.

Man, maybe it's time for you to submit some PR or something to get some attention from the Google team or uncle Gates, the door maker? They'll pay you a load of Frnaklin's to manage their backend servers :D

Good luck..

Josh Permalink
February 19, 2008, 09:56

Very nice article -- one question I was hoping to see answered, though: when I have multiple shells open, how can I have all of their histories end up in .bash_history? It seems that many times logging out in one terminal clobbers history entries previously written when logging out from other terminals.

February 19, 2008, 10:32

Josh, it's pretty easy. I have it done. I'll update the article later today, but here is how to do it:

$ export PROMPT_COMMAND="history -a"
$ shopt -s histappend
MarkS Permalink
February 19, 2008, 15:30

Nice article, the ^R way is quite handy. Do you know a way to make history contain only unique entries? (like ipython)

February 19, 2008, 15:39

MarkS, yes I know a way to make history contain only uniques.

Do the following:

$ export HISTIGNORE="&"

That will make history not to save duplicate consecutive entries!

J. Cunningham Permalink
February 19, 2008, 20:56

From the title I was hoping you would answer a question that has bothered me for a long time: how do multiple xterm/rxvt/aterm/whatever histories interact? No one works in a single xterm, so clearly it is relevant. And if you do different things in different xterms, the histories look different. Yet there is only one .bash_history file in a default setup. Can you explain how this works?

February 19, 2008, 21:27

Cunningham, all the terminals interact with your shell program. The shell program manages the history. The terminals are just computer interfaces for text entry and display, they do not know about your shell history.

I think if you closed all your terminals and run them all, then pressing key-up would display the same command from history.

When you have executed a bunch of commands on each of the terminals and you close them, bash overwrites .bash_history again and again with history in each session.

You should see my previous comment I answered Josh on how to have a unified .bash_history accross all bash sessions (no matter what terminal).

Baishampayan Ghose Permalink
February 20, 2008, 10:06

I have fixed your usage of quotes in the LaTeX file. The modified file is available here:

I also modified the file to generate A4 PDF instead of US Letter.

Baishampayan Ghose Permalink
February 20, 2008, 10:08

Forgot to add: Superb Tips :)

Gabriel Permalink
February 26, 2008, 19:57

Great Tips!

Is it somehow possible to replace more than one occurrence with the "^"-designator?

Dub Dublin Permalink
March 19, 2008, 09:19

Great write-up, You uncovered quite a few tricks I never knew, but you missed a very useful one: "!$" will match the last argument of the previous command. This can be very useful for things like this:

> ls -l /etc/passwd
> file !$
F.Baube Permalink
April 13, 2008, 23:30
# "-l" says use stdout, not a special file
alias h='fc -l; echo r NNN to repeat one, or ; echo r CMD to repeat the last command beginning with CMD'
alias r='fc -s'
# From "man history":
# In the second form ("fc -s"), command is 
# re-executed [..]
# A useful alias to use with this is `r=fc -s', 
# so that typing `r cc'' runs the last command 
# beginning with `cc' and typing `r'' re-executes 
# the last command.
karl-heinz Permalink
April 14, 2008, 10:04

Good infos! Maybe you could also inform about the possibility using HISTORYCONTROL. Regards.

Mike Permalink
May 07, 2008, 14:00

unless ive miss read I cant see on this page where on previous linux flavours you could search for previous commands with slash(/) then use the arrow keys to scroll through these commands but with the newer flavours eg fedora this does not work. Im sure ive seen in the past a solution for this but ive forgotten it :-( anyone know how to get / search and arrow key scroll working in fedora?

Mike Permalink
May 09, 2008, 19:37

Ted - your post does not answer the question I was asking :-(. I know about ctrl+r but thats not the search facility I was looking for.

June 05, 2008, 16:59

@Mike, I'm not positive, but that could be a feature of being in vi mode on the command line rather than the default readline/emacs style key bindings.

There's actually a good post on this blog about vi mode.

In vi, I know you can do a search with "/" and I wouldn't be surprised if you could then up arrow through commands.

Alternatively, most shells that I've used support using the arrow keys to maneuver through history (without using a slash).

Mike Permalink
June 05, 2008, 17:51

Hi Ted,

Ive found that if you 'set -o vi' in your profile you can then do 'esc k' to put you into search mode then do '/cp' for example and then press enter and this will find your last cp command. You can then press 'n' to scroll to the next cp command and so on :-)

windlaser Permalink
June 14, 2008, 03:52

Excellent article, a great amount of new things.
Hm, if you don't mind the question, maybe you know... I often have multiple shells open via GNU Screen, and when I type "halt" to put my system down, the history of the open sessions won't update with the data used in them. Is there any way to force a constant update of the history file (without needing to log out to update)?

Amos Shapira Permalink
June 14, 2008, 13:33

I actually come from the "bang-something" side where it used to be the only way to refer to history back in the tcsh days, and keep surprising my colleagues with my "!:"-fu magic sequences :)

One correction I have is that most (all?) the mentions you made to "!!:x" (e.g. "!!:2") can be actually typed as "!:x" (i.e. one "!" is enough). Only "!!" by itself to repeat the last line and execute it immediately requires two "!".

Amos Shapira Permalink
June 14, 2008, 13:38

Answer to Gabriel about replacing more than one occurrence: you can use the !:s (the "^" is actually mentioned in the manual as a simplified version of "!:s"):

$ echo a b b b c
a b b b c
$ !:gs/b/d/
echo a d d d c
a d d d c

It's all in "man bash", BTW.

Amos Shapira Permalink
June 14, 2008, 13:42

Ah, and also all the mentions of "!:x" not using numbers ("$", "^", "*") do not require the ":", e.g.:

$ echo a b c d
a b c d
$ echo !$
echo d

But "echo !2" will print the 2nd command in the history list, not the 2nd argument in the previous command.

All this squeezing out of unnecessary typing adds up when you type in a hurry and many times.

cjk Permalink
June 14, 2008, 23:47

First of all, C-p and C-n are much easier... the Up and Down cursor keys.

Once you know of Ctrl-R, your use of ! automatically declines drastically, and ^ehco^echo becomes non-existent. With the ! prefix, you have to be absolutely sure that the command is what you want to run, there is no chance to see its expanded form before it is executed—this may be a risk (like when you do !rm). Ctrl-R is much safer as it allows you to see/change the command while entering it. The same aplies to ^ehco^echo — just ^R e h c, then use the arrow keys to change to e c h.

Also, ! is hardly used. Except you count how many commands you are away from your designated command -- ^R to the resuce (again, surprisingly?)

Amos Shapira Permalink
June 15, 2008, 12:35

Response to cjk:
1. Usually a command you want to fix in this way (or just generally want to build up on top of a previous command) is pretty recent in the history so you'll see what your "!" notation is going to catch.

2. If you are not sure what's going to happen after your fix then you can always add ":p" to the end of the command to cause the changed command to be printed and added to the history without actually executing it, then if you are happy with it then do "!!" (or ^R Enter if you insist).

For example:

$ echo a b c d
a b c d
$ ^d^replaced^:p
echo a b c replaced

Notice that the second echo was printed by the shell but wasn't actually executed. Then you can do:

$ !!
echo a b c replaced
a b c replaced

And now it was executed.

I'm not discarding the use of interactive editing altogether - I use it a lot. But there are instances when the "!" notation is more useful. e.g. when you want to use the same argument(s) from a previous command but with a completely different command - interactive editing will require you to erase the old command before you edit the new one, skipping backwards and forwards around the parts you want to keep. With "!" and the various ways to refer to previous command's arguments it's easier and saves lots of repetitive typing (I'm saying this from personal experience, not as a theoretical claim).

June 16, 2008, 06:05

There is a feature in Suse Linux that I have always found useful, you can type the first chars of a command and the the PGUP key, it will take you to the last ocurrence of the command that starts with those chars. If you keep pressing the PGUP key it will jump back in history through the ocurrences of the commands starting with the chars.

Currently Im using Ubuntu, and I really miss that feature.

Do you know how to recreate it?

Amos Shapira Permalink
June 16, 2008, 13:09

Does the string you type have to match the BEGINNING of the command line?

^R/^S will do incremental search but they will match any part of the line, not just the beginning. I couldn't find an interactive way to match the beginning in a search.

Just go through "man bash" (look for a section named "Searching" under "READLINE") to find all the details.

BTW - while looking for an answer for you I found that it's possible to interactively yank arguments from previous line to the current one. It's not the full power of "!" notation but for people who prefer a more visual feedback and are not already accustomed to the old way it might be a good compromise.

staxos Permalink
June 17, 2008, 04:12

I'm surprised no one mentioned this before. This also answers Ix's question (or comes close to it). Put the following in your ~/.inputrc file and save it (not including the dashes):
"\eOA": history-search-backward
"\eOB": history-search-forward
"\eOC": forward-char
"\eOD": backward-char
"\e[A": history-search-backward
"\e[B": history-search-forward
"\e[C": forward-char
"\e[D": backward-char
Now, on the shell, start typing the beginning of a command, and press the Up key. You'll see the history is navigated only within the commands that start with the string you type (I call this the matlab type of history navigation). Very useful if you're used to the Up and Down keys.

HarishVangala Permalink
October 26, 2012, 12:31

Thanks a lot staxos!! Thats Wonderful & simple!!

July 10, 2008, 11:14

Thank all who've posted here! Very useful information!

August 07, 2008, 14:05

This is cool. I wish I had time to read that and memory to retain that.

martin Permalink
September 03, 2008, 17:30

Very good guide - I learnt lots here.

I have a question, which has bugged a few of us for a while and I've not seen an answer to this anywhere yet.

In ksh if you set -o vi and then recall a command and hit v to edit the command with vi, how do you exit without having to a)# out the lines and then quit or b)delete the line/s and then exit.

February 26, 2009, 05:14

Some people may find this useful

$ alias r='fc -s'
$ git branch release-1.120
$ r !:1=checkout
r branch=checkout
git checkout release-1.120
Switched to branch "release-1.120"
February 26, 2009, 05:25

wow, just learnt something by reading the comments above, you can make this one even shorter by omitting the ':' like this:

$ r !^=checkout

I find it much better than the ^^^ and s/// forms as you don't have to retype the argument you wish to replace

Parag Dave Permalink
November 29, 2009, 10:11

When we open several Linux pseudo-Terminals (tty1 to tty6 normally), their combined history is stored in the .bash_history file. I want to have a separate history maintained for each of the terminals. How do we achieve that?

December 05, 2009, 07:53

Parag Dave, try this:

Put the following in .bash_profile (or system wide file /etc/profile)

TTY=$(tty | sed 's|/|_|g')

This should make HISTFILE to be ~/.bash_history_dev_tty1 for 1st, etc.

maryum Permalink
February 06, 2010, 13:45

how to remove the error of readline in closed file handle while using perl scripting in centos 5.3

February 09, 2010, 17:45

i have recently started learning perl.....and having issues when i try to read input from another file. the details of a script that i tried to run are as follows:

i made a text file by the name “text.txt” and the contents were

Then i wrote the following script

open(DAT, "text.txt");
$data_file=" text.txt ";
open(DAT, $data_file);

i have recently started learning perl.....and having issues when i try to read input from another file. the details of a script that i tried to run are as follows:

i made a text file by the name “text.txt” and the contents were

Then i wrote the following script

open(DAT, "text.txt");
$data_file=" text.txt ";
open(DAT, $data_file);
foreach $student (@raw_data)
print "The student $name bearing roll number $roll_no is in class $class";
print "\n";

the script produces no output and displays a message saying
“readline () closed filehandle at line ”
I tried the same with another file by the name “text.dat” holding the same data but it did not work either. Please help me out resolving this issue.

March 01, 2010, 21:06

I'm using this settings,
export HISTSIZE=100000
export HISTTIMEFORMAT='%Y-%m-%d %H:%M '
export ignoredups

history then shows when the command has been issued to the terminal, which could be very usefull information from time to time.

Anil Beniwal Permalink
March 13, 2010, 19:43


I have a query.
Is there a way so that what when somebody erases the command line history, I always have a backup of latest history or is there a way out so that i can have my history saved in two files parallel and doesn't wipe out with history -c.
Our any other option such that i have the logs of all the commands executed on the command line.

Thanks a lot.

paul Permalink
March 18, 2010, 14:01

typo alert: to retrieve previous history lines in vi mode, it's ESC followed by 'k', not by 'h'. (your sentence above is: "In vi mode try CTRL-[ (or ESC) (to switch to command mode) and ‘h‘ (’j‘ for the next command)."

April 16, 2010, 06:32

You haven't made it clear in your sheet that you can do:
$ echo foo bar baz
foo bar baz
$ echo !$ - !^ - !*
baz - foo - foo bar baz

bernard Permalink
September 03, 2012, 17:58

Nice one!

I actually found !* by trial-and-error.

@pkrumins: if you could add those !^ !* to your article, it would be nice :)

By the way, really nice blog and tutorials! I came here by looking for awk one liners, to finally go back to perl thanks to your perl one-liner series :)
Thanks a lot!

Igor Ganapolsky Permalink
April 30, 2010, 13:36

What an awesome tutorial! Thank you.

May 18, 2010, 09:11

Great article, im loving it!

AltairIV Permalink
May 23, 2010, 19:02

I just came across this post. Thanks for the useful summary.

But I'm quite surprised that there's no mention here of the HISTCONTROL variable, which controls the saving of duplicated and space-started lines. The available options (colon-separated) are:

(Don't save commands that begin with spaces, apparently equal to HISTIGNORE="[ ]*")

(Don't save duplicated commands, equivalent to HISTIGNORE="&")

(Combines the previous two options)

(Erase any previous occurrences of a command before saving)

I personally like the last one as it ensures that the most recent usage of the command is saved, rather than the oldest.

Rich Permalink
May 26, 2010, 04:01

Excellent summary thanks!

Jay Zeng Permalink
November 22, 2010, 04:27

Very nice write up! Do you know how to enable sharing history between open tabs within screen?

Excited Guy Permalink
February 09, 2011, 15:55

Nice post, some good shortcuts. I found some other run command shorcuts at take a gander :)

Sarah Duncan Permalink
February 17, 2012, 17:43

This is great! I love it. I'm wondering if you know the answer to a question that's been driving me nuts since switching to bash from tcsh. In tcsh, I can do this:
alias psit 'ps -ef | grep \!* | grep -v grep'
and use it to search for a process:
psit ora
will search for all processes with ora in them, for example. \!* gets me * for the current command line. I can't figure out how to use command line substition on arguments to the current command line in bash. Do you know of a way to do this?

June 14, 2012, 18:37

You can use a function instead:
ps -ef | grep "$@" | grep -v grep

vipul kotkar Permalink
February 21, 2012, 16:51

We can use "history" command to get command line can we get non command line history(i.e. commands run through GUI etc.) ??

chw Permalink
May 21, 2012, 08:41

how to go about to have a (python) script *change* its environment shell's history? i'd like a python script add a command to the history, so it can be more easily executed once the script has finished and control is back to the shell.

Jagadish Permalink
March 27, 2013, 10:24

I am writing a console mode shell scipt.I am trying to read a char in my shell script

echo "Enter the word"
read ch
echo $ch

[Unix@myunix ~]$ ./
Enter the word
Hello wonld^[[D^[[D

Issue: Here u see i miss spelled Hello world as Hello wonld.

I am trying to use left arrow keys to go back to the characted 'n' and change it to 'r'. Here the left arrow keys are pressed 2 times. It is displaying ^[[D instead of going back one character.

Can you pls let me know what changes i need to make to work as i expect.

I am using "GNU bash, version 4.2.39(1)-release"

Thanks and Regards,

January 09, 2014, 23:24

You may want to try "suggest box"-like history for BASH:

saikat Permalink
November 19, 2014, 16:37

I was very pleased to find this site.I wanted to thank you for this great read!! I definitely enjoying every little bit of it and I have you bookmarked to check out new stuff you post.

January 23, 2015, 09:51

Excellent article, a great amount of new things.
Hm, if you don't mind the question, maybe you know... I often have multiple shells open via GNU Screen, and when I type "halt" to put my system down, the history of the open sessions won't update with the data used in them. Is there any way to force a constant update of the history file (without needing to log out to update)?

Prem Permalink
February 28, 2015, 07:39


I'm using this settings,
export HISTSIZE=100000

Very nice article. I hope this will work.

September 28, 2015, 16:08

I was always wondering why my history doesn't show older command e.g. from last monday, only to find out ath HISTSIZE was too small for me.

thomas Permalink
October 30, 2015, 22:31

How do I get history to display comments lines in my .bash_history? According to the bash man page, histchars third character is the character which indicates that the remainder of the line is a comment when found as the first character of a word, normally `#'. The history comment character causes history substitution to be skipped for the remaining words on the line. It does not necessarily cause the shell parser to treat the rest of the line as a comment.

Benjamin Permalink
January 10, 2016, 04:12

I've commented on the Github page for the cheatsheet with this already, but maybe here is more appropriate. This only applies to the downloadable cheatsheet, not the actual article here, as far as I can see.

In your history expansion examples, you sometimes use multiple word designators in the same expansion, which doesn't work for me (Bash 4.3.11, Ubuntu). Minimal example:

$ echo a b
a b
$ echo !!:1:2
bash: 2: unrecognized history modifier

Is this something that used to work, or am I doing something wrong? The Bash manual only ever uses single designators in its examples.

July 07, 2016, 05:49

Thank you so much.I hope to really understand that the wonderful information.

Leave a new comment

(why do I need your e-mail?)

(Your twitter handle, if you have one.)

Type the word "computer_42": (just to make sure you're a human)

Please preview the comment before submitting to make sure it's OK.