history_cleaner.sh
https://gist.github.com/ryan961/2baff64d162a946158405bb59bde1358
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 #!/bin/bash HISTFILE=${HISTFILE:-"$HOME/.zsh_history"} verbose=false print_usage () { echo "Usage: $0 [-f HISTFILE] [-n line1,line2,...] [-o offset] [-r regexp] [-e num] [-v]" echo "NOTE: -n, -r and -e options cannot be used together." echo echo "Delete specific lines from .zsh_history file." echo " -f HISTFILE Specify history file. Default is $HISTFILE ." echo " -n line1,line2,... Delete specified lines. Line number starts from 1." echo " -o offset Delete lines before(-) or after(+) lines specified by -n." echo " -r regexp Delete lines match regexp pattern." echo " -e num Delete last num lines." echo " -v Verbose output." echo " -h Print this help." echo } while getopts ":f:n:o:r:e:vh" opt; do case $opt in f) HISTFILE=$OPTARG ;; n) lines_string=$OPTARG ;; o) offset=$OPTARG ;; r) regexp=$OPTARG ;; e) last_lines=$OPTARG ;; v) verbose=true ;; h) print_usage exit 0 ;; \?) echo "Invalid option: -$OPTARG " >&2 print_usage exit 1 ;; esac done IFS=',' read -ra lines <<<"$lines_string " [[ $verbose == true ]] && echo "Deleting from file: $HISTFILE " if [[ ! -f $HISTFILE ]]; then echo "History file $HISTFILE does not exist" >&2 exit 1 fi if [[ (${#lines[@]} -gt 0 && (-n $regexp || -n $last_lines )) || (-n $regexp && -n $last_lines ) ]]; then echo "Options -n, -r and -e cannot be used together" >&2 exit 1 fi if [[ -n $offset && $offset != 0 ]]; then if [[ ${#lines[@]} == 0 ]]; then echo "You must specify line number with -n when using offset with -o." >&2 exit 1 fi if [[ ${#lines[@]} -gt 1 ]]; then echo "You specify line number with -n (limit 1) when using offset with -o." >&2 exit 1 fi fi if [[ ${#lines[@]} -gt 0 ]]; then if [[ -z $offset || $offset == 0 ]]; then [[ $verbose == true ]] && echo "Deleting lines: ${lines[*]} " for line in "${lines[@]} " ; do if [[ $(wc -l <"$HISTFILE " ) -lt $line ]]; then echo "Line $line does not exist" >&2 exit 1 fi done for ((index = 0 ; index < ${#lines[@]} ; index++)); do line=$((lines[index] - index)) delete_line=$(sed -n "${line} p" "$HISTFILE " ) [[ $verbose == true ]] && echo "Deleting line [${line} ]: $delete_line " awk 'NR != ' $line ' {print}' "$HISTFILE " >tmp && mv tmp "$HISTFILE " done else if [[ $offset -gt 0 ]]; then first=${lines[0]} last=$((first + offset)) else first=$((lines[0 ] + offset)) last=${lines[0]} fi [[ $verbose == true ]] && echo "Deleting range: $first to $last " for ((i = first; i <= last; i++)); do delete_line=$(sed -n "${i} p" "$HISTFILE " ) [[ $verbose == true ]] && echo "Deleting line [${i} ]: $delete_line " done awk 'NR < ' "$first " ' || NR > ' "$last " ' {print}' "$HISTFILE " >tmp && mv tmp "$HISTFILE " fi exit 0 fi if [[ -n $last_lines ]]; then [[ $verbose == true ]] && echo "Deleting last $last_lines lines" total_lines=$(wc -l <"$HISTFILE " ) first=$((total_lines - last_lines)) for ((i = first; i < total_lines; i++)); do delete_line=$(sed -n "${i} p" "$HISTFILE " ) [[ $verbose == true ]] && echo "Deleting line [${i} ]: $delete_line " done awk 'NR < ' "$first " ' || NR > ' "$((total_lines-1) )" ' {print}' "$HISTFILE " >tmp && mv tmp "$HISTFILE " exit 0 fi if [[ -n $regexp ]]; then matches=$(grep -n -E "$regexp " "$HISTFILE " | cut -d: -f1) [[ $verbose == true ]] && echo "Deleting lines match '$regexp ':" $matches i=0 for line_number in $matches ; do line=$((line_number - i)) delete_line=$(sed -n "${line} p" "$HISTFILE " ) [[ $verbose == true ]] && echo "Deleting line [$line_number ]: $delete_line " awk 'NR != ' $line ' {print}' "$HISTFILE " >tmp && mv tmp "$HISTFILE " i=$((i + 1 )) done exit 0 fi if [[ $# -eq 0 ]]; then print_usage fi
This is a bash script to delete specific lines from $HISTFILE
( .zsh_history ) file.
It provides several options to specify which lines to delete:
-n: Delete specified line numbers
-o: Delete a range of lines, used together with -n
-r: Delete lines matching a regular expression pattern
-e: Delete last N lines
The script also supports:
Specifying a different history file with -f
Print verbose output with -v
Print help message with -h
The implementation uses awk to filter out target lines and redirect to a tmp file, then replace original file.
Some notes on usage:
Line numbers start from 1
-n, -r and -e options cannot be used together
This provides a flexible way to clean up .zsh_history by deleting unwanted lines.
Please let me know if you would like me to modify or expand the introduction.