Understanding Bash History
symkat.com
symkat.com
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.
i always wondered whether linux had such terrible man pages because nobody read them, or whether nobody read them because they were so terrible.
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.
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
*nix hacking ~ heart surgery? Who knew.
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?
!! -delete
(But it still doesn't address the main issue.)
now you can keep a given command from history
find ...
<space>!! -delete
Now it remains to be seen whether I can train myself to always precede "unsafe" find commands with a blank.
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:
$ 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://hintsforums.macworld.com/archive/index.php/t-82501.ht...
'stty -iexten' fixed it for me on my Mac.
^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.
$ 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 !!
$
"\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 [ ! -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".)
Anyone know of a utility for saving annotations about the bash history lines? (Date, comments, current directory, etc.?)