Skip to content

Musings of an Anonymous Geek

Made with only the finest 1's and 0's

Menu
  • About
  • Search Results
Menu

The bash history command

Posted on February 19, 2009 by bkjones

Sometimes I run through the search terms people use within my site, or to get to my site, and I see some interesting stuff. Over the years, I’ve written perhaps hundreds of technical blog posts and articles at various sites and in magazines (and a book), but I have never once touched on the “history” command. In spite of that, someone searched for “what does the history command do”, and somehow landed on this site. Here’s a quick overview I give people who take my Linux From the Ground Up class (I’m currently booking on-site training for the July-September period, by the way).

The history command is built into the bash shell (and zsh, and other shells as well). This means you won’t find it sitting around in /usr/bin. You also will get funny results if you run “man history”, which will bring you to a man page about all of your bash builtins instead of one specific man page for “history”.

Typical (Simple) Usage

You have a shell session open. You’ve been doing some work, and you’ve run several commands. One of the commands was a long nasty compilation command which contained environment variable settings, lots of flags, and references to specific files. It was long, and you don’t want to type it again, but you have to because the compilation failed. You’ve fixed the issue, and want to run the same compilation command.

Instead of typing all of that stuff in all over again, you have a couple of choices (more really, but we’re starting slowly):

  1. If you’re on a machine that uses readline capabilities, you can use the up arrow to move back through your previous commands. This is inefficient.
  2. You can type “history” at the command line

Typing “history” at a shell prompt by itself will print a numbered list of commands you have run. Let’s say your compile command is number 50 in the list. Now typing “!50” at the command prompt will run that command again without you having to type in the whole disgusting thing.

More Useful Usage of “history”

If you know that you’ve only run, say, “netstat” with one set of arguments, and you keep running it over and over again, you can use a shortcut by just typing “!netstat”. That will run that last command in the history that starts with “netstat”. This is prone to error if you run a command often, but with different arguments.

If you need to run a long ugly command again immediately, but you need to change just a single argument, you can also use carets to do string substitution. So, if you just ran “netstat -plant | grep :80” and you now want to check for “:22” instead of “:80”, instead of typing in the whole command again, you can just type “^80^22”. Note that if you ran, in this order:

  1. netstat -plant | grep 80
  2. netstat -plant | grep 111
  3. ^80^22

You’ll get an error. It only works on the last command you ran.

You can also search through your command history in bash using Ctrl-R. This will alter your prompt, and when you start typing the command you’re looking for, it will do an incremental search through your command history and put what it finds on the line. When the right one pops up, hit enter, and the command will run. Note that if you need to make a quick edit to the command before it runs, moving the cursor will paste the command on your prompt, which will return to normal, and you can edit it before hitting enter.

History Command Quirks

There’s one quirk of history that bites lots and lots of people, myself included. If you’re aware of it, you can avoid it biting you. You see, bash keeps its command history for the current shell in memory, and then writes out that memory to your ~/.bash_history file… when the shell exits. There are times when this can be problematic, for example if you open another shell and want to run a command you just ran in the first shell. It won’t be in your history, because the first shell is still open, so its history hasn’t been written out to disk yet.

There are two ways to get the history that’s in memory onto disk. The first is to exit the first shell. The second is to run “history -w” in the first shell. Either will write the history to the ~/.bash_history file, but be forewarned that doing this overwrites anything that was previously in the ~/.bash_history file! Maddening, isn’t it?

If you configure bash ahead of time by adding “shopt -s histappend”, you can tell bash to append, rather than overwrite the history file.

Another quirk of how history is setup to work by default is that it saves every single command you type. If you open a terminal and type nothing but:

ls
cd
cd -
ls
ls -l

Those all take up space in your history. The environment variable HISTSIZE can be set to something like 10,000 to account for this if you want. It’s set to 1000 by default on Red Hat systems. The other thing you can do is tell the history mechanism to conserve space in history by ignoring certain commands, patterns, duplicates, etc, using HISTCONTROL and HISTIGNORE

HISTCONTROL can be set to “ignorespace”, which will not put commands starting with a space in history. I’ve never been able to train myself to type a space before ‘ls’, so I’ve never used that setting. Slightly more useful is the “ignoredups” setting, which will stop the command you just ran from getting into history if it’s a duplicate of the command run just before it. Still not what I’m looking for. Better is “erasedups”, which will delete all previous instances of that command in history before writing the current command to history.HISTCONTROL can take multiple values, separated by colons.

If you just want to make sure “ls” commands never get written to history, you can just use HISTIGNORE for that. It can be set to a colon-delimited list of patterns or commands that, if matched, disqualify the command from being entered into history. So, you can do something like this:

HISTIGNORE=ls:cd:df:du

Note that these are essentially command matches, and must match exactly, starting from the beginning of the line. So, ” du” (with a space in front) will be put into the history list, and so will “du -h” (no preceding space) will also make it. You can use, for example, HISTIGNORE=du* if you want to catch that command and anything that follows it.

Really Hardcore History

There’s a presentation online that talks about way more nitty-gritty details of history than I have time to cover. It’s great work, though, so I recommend you check it out here.



Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to share on Tumblr (Opens in new window) Tumblr
  • Click to share on Facebook (Opens in new window) Facebook

Recent Posts

  • Auditing Your Data Migration To ClickHouse Using ClickHouse Local
  • ClickHouse Cheat Sheet 2024
  • User Activation With Django and Djoser
  • Python Selenium Webdriver Notes
  • On Keeping A Journal and Journaling
  • What Geeks Could Learn From Working In Restaurants
  • What I’ve Been Up To
  • PyCon Talk Proposals: All You Need to Know And More
  • Sending Alerts With Graphite Graphs From Nagios
  • The Python User Group in Princeton (PUG-IP): 6 months in

Categories

  • Apple
  • Big Ideas
  • Books
  • CodeKata
  • Database
  • Django
  • Freelancing
  • Hacks
  • journaling
  • Leadership
  • Linux
  • LinuxLaboratory
  • Loghetti
  • Me stuff
  • Other Cool Blogs
  • PHP
  • Productivity
  • Python
  • PyTPMOTW
  • Ruby
  • Scripting
  • Sysadmin
  • Technology
  • Testing
  • Uncategorized
  • Web Services
  • Woodworking

Archives

  • January 2024
  • May 2021
  • December 2020
  • January 2014
  • September 2012
  • August 2012
  • February 2012
  • November 2011
  • October 2011
  • June 2011
  • April 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • September 2010
  • July 2010
  • June 2010
  • May 2010
  • April 2010
  • March 2010
  • February 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • August 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • November 2007
  • October 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007
  • February 2007
  • January 2007
  • December 2006
  • November 2006
  • September 2006
  • August 2006
  • July 2006
  • June 2006
  • April 2006
  • March 2006
  • February 2006
  • January 2006
  • December 2005
  • November 2005
  • October 2005
  • September 2005
  • August 2005
  • July 2005
  • June 2005
  • May 2005
  • April 2005
  • March 2005
  • February 2005
  • January 2005
  • December 2004
  • November 2004
  • October 2004
  • September 2004
  • August 2004
© 2025 Musings of an Anonymous Geek | Powered by Minimalist Blog WordPress Theme