78

The history command lists out all the history for the current session. Like:

1 ls 
2 cd /root
3 mkdir something
4 cd something
5 touch afile
6 ls
7 cd ..
8 rm something/afile
9 cd ..
10 ls
11 history

In order to search items of interest, I can pipe history with grep like

history | grep ls
1 ls
6 ls
10 ls

I can also view last 3 commands like:

history 3
11 history
12 history | grep ls
13 history 3

But how do I get a specific range of history? For example something like:

history range 4 7
4 cd something
5 touch afile
6 ls
7 cd ..
2
  • You could list the last x commands then pipe to head.
    – Bratchley
    Commented Jun 22, 2016 at 3:52
  • @Bratchley: For that I'd have to know how many last commands to go to. Consider this, my history | grep something shows results of commands numbered 123 234 345 in history and I may not know the number of last command executed (history in this case). My last command could be numbered 400, 500 or whatever. So first I have to check that number, figure out the difference, list the last x commands and then pipe to head Commented Jun 22, 2016 at 3:59

6 Answers 6

123

Instead of history, you can use fc, which allow you select range:

fc -l 4 7
3
  • 7
    It even accepts negative numbers to count from the end, like fc -l -16 -10. Commented Jun 22, 2016 at 8:39
  • 3
    hmm, wonder why we need a whole new command instead of just arguments to the actual command...
    – Ringo
    Commented May 10, 2019 at 1:56
  • I had never heard of fc before, so THANK you! I like the fact that it can load a previous command into my default editor for editing and then when I quit the editor it runs the edited command.
    – cptully
    Commented Apr 18 at 21:57
20

If you must use history command, pipe it through sed or awk:

history | sed -n '10,20p'

history | awk 'NR >= 10 && NR <= 20'

Otherwise cuonglm's answer is better option.

3
  • @questionto42standswithUkraine I've deleted my comment which didn't serve much purpose, but the 15 and 25 in this pipeline should be preceded by a dash. Since they aren't, tail and head assume they are files they should be reading from, hence the error message
    – Aaron
    Commented Apr 5, 2022 at 17:31
  • 2
    @questionto42standswithUkraine I'm honestly not convinced that head+tail has any advantage over sed -n "${start},${end}p". If you are, I invite you to add an answer. Otherwise I'll think about adding one but I won't promise anything
    – Aaron
    Commented Apr 5, 2022 at 17:55
  • @questionto42standswithUkraine I don't want to post an answer, please stop trying to convince me. Just post the damn answer yourself
    – Aaron
    Commented Apr 15, 2022 at 9:04
3

Using history with a grep on the line numbers around the command I'm looking for works best for me.

For instance I'm looking for what I did around ping mybox, more or less 20 lines.

$ history | grep "ping mybox" 20325 ping mybox

That's line 20325 so I just have to grep the lines starting by a number in the [20320..20339] range.

$ history | grep ^203[2-3][0-9]

1
  • 1
    (1) You say “more or less 20”, but your example shows −5 and +14.   (2) This doesn’t work for me, because history numbers seem to have leading spaces. Commented Oct 6, 2017 at 10:06
1

Here is an answer that uses the history command with a parameter.

Credits go to this user who did not want to make his now deleted comment an answer. I am taking over since I think that the now deleted comment should be an answer on its own.

Most used

history | tail -5 

gives you the last 5 lines. Which should be all you need in everyday programming, change to the lines you need of course. I am using this by heart from the start, easy to remember.

Further

history | head -5 

gives you the first 5 lines,

history | tail -10 | head -5

gives you the second last 5 lines

history | head -10 | tail -5 

the lines 7 to 11. You need

history | head -8 | tail -5

to get the second 5 lines, meaning 6 to 10, strange, but no big issue to always add +2 on the head in such cases and you do not need the head of the history anyway or a chosen slice of it if you just want to shrink the full history down to the normally younger commands.

0

If you must use 'history', this is a more correct sed-based version, for history lines 4-7:

history | sed '/^4 /,/^7 /!d;/^7 /q'

This captures the original poster's intention to print the nth lines of history, not the nth lines of output of the history command. Almost all of the time the two will not be the same. For example, the numbers that the poster cares about in this history output:

... 20 preceding lines.
12134 ls dataDir
12135 ls myDir
12136 ls something
... some more lines

are 12134,12135,12136, and not 21,22,23, and the sed command should capture that, in this case something like this:

history | sed '/^12134 /,/^12135 /!d;/^12135 /q'

The specific format for the numbers:

'/^n[space]/'

captures the intention that the number is at the beginning of the line, and that it is followed by a space. (As I look at this I think the space is unnecessary, but it makes me feel better, ha.)

And yes, as @G.Gabunia says above, fc is easier

-1

Assuming you want the range 4 to 7:

history  4 | head -n 3

In this method, you can generally get history from n to m with:

history n | head -n m-n

Note that the head command is literally head -n followed by a number, as shown in the first command.

1
  • 2
    (1) No, history 4 gives the most recent four commands, not everything starting at command #4.  (2) No, to get thing # n through thing # m, you need to grab m − n+ 1 things. … … … … … … Besides, all of this has been covered already. Commented May 16, 2022 at 17:21

You must log in to answer this question.

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