2

I rely on my history file for previous commands, especially ones that are long with many parameters. Once I find the command and its line number(nn) I use !nn to run it. I prefer to see the full output from the search rather than doing an in-line reverse search.

To do this I search through it with history | grep some_text

However I tend to get a lot of output due to duplicate entries (differing only in their line numbers). As my history grows this gets worse over time.

How could I get a list of just the unique commands that I could then use with the ! recall command operator?

I tried history | uniq | grep some_text but that doesn't work because of the line numbers.

I can do history | cut -b8- | uniq and that does show just the commands.
However when I add sort I get $ history | sort sort: string comparison failed: Illegal byte sequence sort: Set LC_ALL='C' to work around the problem. sort: The strings compared were 5359 \253' and 5360 x'.
Also the line numbers are gone which I would actually want for the !line-number command

Ideally I would like this to happen each time I do my history | grep - which I do so much I have an alias hg='history | grep ' so I could add any solution to that.

Less ideal, but still of interest would be the ability to run an ad-hoc program which would actually make the history file entries unique (again, dealing with the line numbers issue) so that only the most recent history command of any given command is retained). presumably by deleting the other lines. But would deleting lines in the history file this way mess up the way the file is used by the system?

3 Answers 3

2

You can say:

history | awk '{$1=""; sub("^ ", "", $0)}1' | sort -u

to get a list of unique entries in the history.

However, you can also set HISTCONTROL to avoid duplicates in the history:

HISTCONTROL=ignoredups:erasedups

Quoting from the manual:

HISTCONTROL

A colon-separated list of values controlling how commands are saved on the history list. If the list of values includes ‘ignorespace’, lines which begin with a space character are not saved in the history list. A value of ‘ignoredups’ causes lines which match the previous history entry to not be saved. A value of ‘ignoreboth’ is shorthand for ‘ignorespace’ and ‘ignoredups’. A value of ‘erasedups’ causes all previous lines matching the current line to be removed from the history list before that line is saved. Any value not in the above list is ignored. If HISTCONTROL is unset, or does not include a valid value, all lines read by the shell parser are saved on the history list, subject to the value of HISTIGNORE. The second and subsequent lines of a multi-line compound command are not tested, and are added to the history regardless of the value of HISTCONTROL.

1
  • +1 Looks good. Just to be clear, for 'existing history' the erasing of dups doesn't happen until you actually issue the command once (with this setting). This is the point that the cleanup takes place. So doing history just after applying this change will still show duplicate commands. Once the command in question is actually issued again, then it'll only show once in history going forward. Apr 7, 2014 at 14:42
0

You can parse .bash_history file, instead of using history command. Here's an example in awk:

awk '!x[$0]++' .bash_history | nl

But like @devnull's answer, you should use HISTCONTROL to avoid duplicated command and also command which start with spaces:

HISTCONTROL=ignoreboth
0

on my system, uniq has the option of skipping fields.

history | uniq -f 1

gives me a unique listing of my history with line numbers

my version:

uniq (GNU coreutils) 8.15

However, this only omits concurrent duplicates, so I would actually sort the history output, then uniq it:

history | sort -k 2 | uniq -f 1 | sort -n

The last sort, is optional, it will re-order the sorted, unique entries by the command number

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .