Hacker News new | past | comments | ask | show | jobs | submit login
Understanding Bash History (symkat.com)
95 points by Altreus on Sept 16, 2010 | hide | past | favorite | 27 comments



Heh. This is funny timing, as .bash_history made me feel like an idiot just yesterday morning.

I was sitting here between queries and I thought 'y'know, all I ever do with history is grep for things. I wonder what else I can do?' When I want to learn about something quick, I usually start with the built-in help; so I did

history --help

The built-in help for history, unfortunately, is woefully inadequate; this was the output:

history: usage: history [-c] [-d offset] [n] or history -awrn [filename] or history -ps arg [arg...]

I said to myself: "Hmm. Wonder what those do?" -- and in a moment of bash stupidity, I thought: "well, let's try it!"

history -c

There's no output from that command, but it didn't take long to figure out what it does. It deletes your entire bash history, clearing the history in RAM and emptying .bash_history.

Since I use history all the time, I panicked. Holy crap! What have I done? I spent a few minutes internalizing the obvious lesson that everybody knows - never run commands without knowing them first. Thankfully, though, I had another bash open at the time. And after I'd beaten myself up over it, I thought for a moment, jumped over to the other shell, and did:

cd && history | cut -c 8- >> .bash_history

... because (after all) the evil, evil history -c command doesn't kill the history from RAM in other shells.

Lucky me.


A heart surgeon once told me, surgery is not about how good you are at staying out of trouble, but how good you are at getting out of trouble. Eg, shit happens, the survivors are the ones who can deal with it.

*nix hacking ~ heart surgery? Who knew.


The built-in help for history, unfortunately, is woefully inadequate; this was the output:

i always wondered whether linux had such terrible man pages because nobody read them, or whether nobody read them because they were so terrible.


Well, since 'history' is a shell builtin, the thing to do would be 'help history', which actually gives a pretty thorough explanation of it. (And it's also explained pretty fully if you look at the actual man page for bash.) What the grandparent commenter saw was in fact just the brief "you invoked this command wrong" synopsis message, since '--help' isn't a flag recognized by the 'history' command (assuming his version of bash behaves similarly to mine).

Sure, there are some more obscure, less-commonly-used commands that are poorly documented, but for the basic stuff (and yes, that includes bash), I've found man pages to generally be a pretty good source of information.


Yes, the actual linux documentations are actually very good. I live on a server with hacked-together shell commands that are badly-documented, so I'm in the bad habit of doing the --help thing (the default around here).

The man pages are indeed very good. It's also worth noting that the Gnu people tend to prefer info pages - and 'history' is traditionally a Gnu-maintained command (as part of binutils) - so you'll get the absolute best documetation I know of (long explanations, interesting permutations, obscure hacks) if you do:

info history


I use history a fair amount, and I've noticed an issue that none of these articles mention.

For history to be useful, you need to be able to reuse previous commands without giving them much thought; in the time it takes to think in detail about a command, you usually could have typed a new one without using history. As a result, commands that are reused via the history mechanism need to be "safe", with no hidden pitfalls.

For example, I use "find" a lot. A normal thing to do with "find" is to get a list of files to delete. Now, I could do that with "find ... -exec rm" or "find ... xargs ... rm", but that leaves me with an unsafe "find" command in my history, just waiting to bite me when I try to reuse it. If, some time later, I type "!fi" without thinking much about it, I might end up deleting some random files. Not good.

My solution, in this particular case, is never to do "find ... rm" on a single line. To remove a list produced by "find", I do "find ..." and then "rm `!!`". That runs the "find" command twice, of course, but the second time, everything has been cached, so it's very fast. (The real disadvantage is that the delay -- for the first "find" -- occurs in the middle of what is conceptually a single operation: after I've typed the "find", but before the "rm".)

So, has anyone else run into this issue? Thoughts? Other ways of dealing with it?


find ...

!! -delete


Ah, didn't know about that one. Thanx.

(But it still doesn't address the main issue.)


HISTCONTROL="ignorespace"

now you can keep a given command from history

find ...

<space>!! -delete


That's a nice feature.

Now it remains to be seen whether I can train myself to always precede "unsafe" find commands with a blank.


While what is covered is very well presented, post doesn't mention `shopt -s histappend`, which is one of the most important things to note when dealing with history in bash.

Also useful: you can append :s/foo/bar to bang commands to substitute once, :gs/foo/bar to substitute globally. `man bash` History Expansion section has the other options under subheading 'Modifiers'.

I highly recommend the following resource -- it's what really got me saving keystrokes:

http://www.ukuug.org/events/linux2003/papers/bash_tips/


I learnt something handy in BASH recently - operate-and-get-next (Ctrl-o). If you type:

  $ echo one
  one
  $ echo two
  two
  $ echo three
  three
Then up-arrow back to 'echo one'. Then press Ctrl-o instead of enter it will execute the command and display the following one in your history ('echo two' in this case).

Very handy for replaying a series of commands.

http://www.faqs.org/docs/bashman/bashref_101.html


This is in the man page for bash on Snow Leopard, but it doesn't seem to actually work. Does anyone know why?


There's a solution here:

http://hintsforums.macworld.com/archive/index.php/t-82501.ht...

'stty -iexten' fixed it for me on my Mac.


Here are some of my other favorites:

^foo^bar replaces the foo in the last command with bar

example: less setup.conf, ^less^vim

alt+. recalls the last argument of the last command (in emacs mode, anyway)

example: less setup.conf, vim alt+.

As mentioned, Ctrl+R is great for history searching. Repeatedly pressing Ctrl+R goes to the next result, and you can use the arrow keys to edit.

cd - goes to the last directory. It handles most of the use cases for pushd and popd.


As far as these little shorthands go, you've left out the one I use most all day long; the ever-handy !:-, which means 'the last command minus the final argument':

$ cat ~/my_huge_dataset.csv | tr '\|' ',' >> testing.csv

$ !:- for_real_this_time.csv

>> cat ~/my_huge_dataset.csv | tr '\|' ',' >> for_real_this_time.csv

$

This is really, really handy for me - particularly in two situations: first, when (like above) I'm testing a command by outputting to a random off-server file first; and second (the more often) when I'm running the exact same process on a dozen different files, just pasting the filenames onto the command line. It's really handy to be able to use !:- all the way down for every one.

Oh, and theres's also this: !! - which means 'the last command exactly.' That can be handy, too:

$ rm /usr/lib/libutil.so

>> m: cannot remove `libutil.so': Permission denied

$ sudo !!

$


I like the !:-, even though it's super ugly. It's the perfect complement to alt+. !! is a classic, but the article mentions it.


I like mapping page up and page down to history-search-backward and history-search-forward in /etc/inputrc or ~/.inputrc. It works much like the bang commands. Ubuntu and Debian have the appropriate lines commented out; other distros might enable such a mapping by default (Mandriva did when I used it last).

  "\e[5~":        history-search-backward
  "\e[6~":        history-search-forward
Some other useful entries:

  # ctrl-left, ctrl-right
  "\e[1;5C":forward-word
  "\e[1;5D":backward-word
  "\e[5C":forward-word
  "\e[5D":backward-word
  "\e\e[C":forward-word
  "\e\e[D":backward-word


Mentioned in the comments, but another extremely useful feature is if you type ctrl+r and start typing a command, it will give you the last command you ran that contains that substring.


This is the main way I use the history, other than just cycling through the last few commands with the up arrow. I've just never found the bang commands useful enough to be worth remembering for the relatively few times they would be useful. ADDED: Note that I have a pretty large .aliases file that I have profile run when I log in. Any complicated command lines that I run at all frequently get aliased and added to the list. Or for longer lines I convert them to a script in my $HOME/bin.


Since everyone's sharing their bash history tips here, I thought I'd throw one out. I've taken to tossing the following lines in my root user's .bashrc over the last few years (which I adapted from a colleague years ago):

  [ ! -d $HOME/.history ] && mkdir $HOME/.history
  set -- `/usr/bin/who -m`
  HISTFILE="$HOME/.history/`/bin/date +%Y-%m-%d.%T`.`/bin/hostname -s`.$$.$1"
You end up with a filename something like:

  2010-09-17.13:53:27.foohost.14379.logic
The idea is that each shell session gets it's own history file, and the files are kept "indefinitely"; ie. whenever I manually get around to cleaning them up. Keeping that history around is cheap (we're talking about a few megabytes over the life of a given system), and can be invaluable in figuring out the how and why of a particular change even months later.

It also serves the purpose of making a best-effort attempt at gathering who "owned" that session (ie. who su'd to root); with multiple admins, this can be pretty handy. It's easily bypassed (and console logins will just show up as "root"), so using this as any kind of audit system would be ridiculous; it's just a useful way of going back in time to see who did what (usually looking of work I did myself, to see how/why I might have made a particular change months ago).

The one downside: you lose cross-session history. In practice, especially with multiple users accessing a shared account (multiple admins, etc), this hasn't really bothered me much, as getting someone else's history is annoying anyway. But, some people lean pretty hard on their bash history, and I definitely wouldn't do this for a personal account. (There, I'd just do "shopt -s histappend".)


I used Linux for years without knowing about the bash history file (though I knew about hitting the up arrow). As soon as I discovered this file, I looked up how to set it to save all my history forever without rollover - what a good resource it would be to have all the commands I've ever used!

Anyone know of a utility for saving annotations about the bash history lines? (Date, comments, current directory, etc.?)



Thanks for the link! I've been looking for a writeup on bash history features for a while. These things are very useful day-to-day.


I learned a lot from this article. It is very useful for novices such as myself. My uparrow key thanks you for writing this.


If you're hitting the up arrow more than a few times, you could easily see search your history instead with "history | grep somestring", or, as someone else mentioned, Ctrl+R and start typing a command.


Slightly misleading title. I expected a tale of ancient hackers, writing code and making decisions, some of which were good, and others that today we regret.




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: