5

Fooling around with Linux on my Pi and ran into this problem. I found that you can remove a certain line with the command history -d linenumber but what if I want to remove a range (which I think is much more practical)? So I looked up how to loop in several places. Both ways of looping worked for an echo but not for the history command. I think it's because "history" is not actually a command. But why does this matter? Is there a simple way of doing this? I never knew looping was possible in Linux bash so now I'm pretty curious! Here's what I did:

pi@raspberry:~$ for ((i=258;i<=262;++i)); do "history -d $i"; done; // which is incorrect due to quotes, giving: -bash: history -d 258: command not found -bash: history -d 259: command not found -bash: history -d 260: command not found -bash: history -d 261: command not found -bash: history -d 262: command not found

This below should work (but it doesn't):

pi@raspberry:~$ for i in {5..10}; do history -d $i; done; -bash: history: 5: history position out of range

I found an article here: https://superuser.com/questions/649859/history-position-out-of-range-when-calling-history-from-bash-script

... but they were not clear at all and said something along the lines that it needs to be sourced instead of executed, which actually means nothing to me. If it can't be done through the command line just say so. Otherwise, I am going to be brushing up on Python, and if that's a logical way of doing it, it'd be nice to know.

Thanks

2
  • The second command fails because there is no entry at offset 5. Check history where it starts and ends.
    – Freddy
    Commented May 25, 2020 at 0:59
  • Hint: If you delete position 10 in a list, the entry in position 11 moves to position 10 if the entry in position 11 existed.
    – Cyrus
    Commented May 25, 2020 at 1:04

2 Answers 2

12
for ((i=258;i<=262;++i)); do "history -d $i"; done;

as you said, is simply not working due to quotes

for i in {5..10}; do history -d $i; done;

is working, but you must ensure to have entries from 5 to 10, which in your examples, you don't have.
Take into account that every item you remove, the position indexes of the other items scale down of one.

Basically you should reverse loop items:

for i in {10..5}; do history -d $i; done;

to not be affected by the position index changes while looping.

Edit
As Cyrus suggested, there's another approach.
You want to remove items from 258 to 262, a total of 5 entries (262 is included)
You can delete 5 times the entry at position 258.
Taking advantage of the index scaling down of one every time you delete an item:

  • the first time, you delete the item 258
  • the second time, you delete the ex-item 259, that has scaled down to 258
  • the third time, you delete the ex-ex-item 260, that has scaled down to 259 (in the first delete) and to 258 (in the second delete)
  • the fourth time, you delete the ex-ex-ex-item 261, that has scaled down to 260 (in the first delete), to 259 (in the second delete) and to 258 (in the third delete)
  • the fifth time, you delete the ex-ex-ex-ex-item 262...
3
  • 1
    Yep, as Cyrus hinted in his comment. So the way I was doing it I would delete every other command since the stack becomes shorter and the variable increments at the same time, each loop. Cool! I guess now I see why some would suggest just do the loop for however many histories to delete, without any variable.
    – Tomi Fodor
    Commented May 25, 2020 at 8:08
  • I edited the message trying to explain the other method to delete items Commented May 25, 2020 at 19:37
  • Great answer, but could you post some code illustrating the second example? I keep running into a history position out of range error. Commented Aug 24, 2020 at 1:23
4

Assuming the entries exist.

If you want to delete the entries 258 to 262, then delete the entry 258 five times.

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.