Marco A. Pivetta
Marco A. Pivetta

Reputation: 36

How to create a Bash script to delete a specific number of lines from history starting at a given position?

Question: I'm trying to create a Bash script that deletes a specified number of entries from the history, starting from a given position. The idea is to make it easier to clean up portions of the history interactively.

What I've tried:

  1. I initially attempted a for loop using history -d to delete the entries in a range, but I faced issues with history line shifts during the deletion process.
  2. I then tried setting up the script as a function in .bashrc, to ensure the history could be accessed directly in the interactive shell. While this allowed me to delete entries, the function didn’t handle larger ranges correctly or threw "history position out of range" errors.
  3. Another attempt involved reloading history with history -a and history -r before and after deletion commands to keep the entries synced. This also yielded inconsistent results, particularly when I tried to delete from specific positions in larger history ranges.

Current Challenge: The main issue is that the script either fails to delete the specified number of lines accurately or doesn’t start deleting from the correct position due to shifts in history entries. I’d appreciate any guidance on how to create a stable Bash script that consistently deletes a chosen number of lines starting at a specified history position.

What I Tried:

  1. For Loop with history -d: I attempted to use a for loop with history -d to delete a specific range of entries. For example, starting from a certain position in history, I tried deleting the next specified number of lines. However, I encountered issues with the history line numbers shifting as entries were deleted, which made the loop unreliable.

Here’s one of the versions I tried using a for loop with history -d, starting from a given history position:

N=10      # Number of lines to delete
START=50  # Starting position

for ((i=N-1; i>=0; i--)); do
    history -d $((START + i))
done

This approach didn’t work as expected because the history line numbers shift each time an entry is deleted, which makes the loop unreliable.

  1. Bash Function in .bashrc: To keep the script within the interactive shell, I moved it to .bashrc as a function, assuming that working directly with the shell's history would improve reliability. This allowed partial deletion, but it still failed to delete the exact number of entries and sometimes returned "history position out of range" errors.

I also tried adding the script as a function directly in .bashrc:

delete_history_range() {
    local N=$1
    local START=$2
    for ((i=N-1; i>=0; i--)); do
        history -d $((START + i))
    done
}

This allowed me to call the function interactively, but I faced issues with larger ranges, and sometimes I got "history position out of range" errors.

  1. Reloading History with history -a and history -r: I also tried adding history -a (to append recent commands to the history file) and history -r (to reload it) before and after each deletion command. This aimed to keep the history synced with the shell's current session, but it produced inconsistent results, particularly with larger ranges.

What I Expected:

I expected a non-interactive solution that could delete an exact number of entries from history, starting at a given position, without manual input. Ideally, the script would reliably handle shifts in line numbering as entries are deleted, without causing out-of-range errors.

Ps.: I came across this question on Stack Overflow, which addresses deleting the last entry in the Bash history with a script. However, my question is a bit different: I’m looking for a way to delete a specific range of entries from history, starting at a given position.

I've tried various approaches, but due to history line shifts and "out of range" errors, I'm struggling to find a reliable solution. While the other question helped me understand how history -d works for single entries, I need a solution that can handle deleting multiple entries in a specified range, starting from an arbitrary point in the history.

Upvotes: 1

Views: 79

Answers (2)

Antoine O
Antoine O

Reputation: 181

By using a combination of tail and head you should achieve it

Use head by getting all but the X last line of a file named file.txt .

head -n -X file.txt

It should work for .bash_history too and this could do the trick ?

head -n -X .bash_history > .bash_history

Use tail to keep the Y last line of a file named file.txt .

tail -n Y file.txt

you could combine this to have a script that create 2 temp files then merge them to .bash_history

Upvotes: 0

LMC
LMC

Reputation: 12822

Deleting entries in reverse order avoids the line shifting issue since the lines will be shifted below the highest entry (the first deleted) in the range but not the others

for i in $(seq 1734 -1 1729); do history -d "$i";done

to print a range of history entries

fc -l 1729 1734

Using OP's for loop and starting at the highest record

N=6; START=1734; for ((i=START; i>((START-N)); i--)); do echo "Deleting history event #$i"; history -d $i; done

Out

Deleting history event #1734
Deleting history event #1733
Deleting history event #1732
Deleting history event #1731
Deleting history event #1730
Deleting history event #1729

Upvotes: 0

Related Questions