# This bash script must be used with 'source' or '.'
# and so it does not need to be made executable.
# . scriptname Display last 35 history lines (default)
# . scriptname n Display last n history lines
# The lines are displayed with their line numbers.
# Enter a list of the lines to be deleted
# An example of a line list is 90 45-56 78-
# 90 Delete line 90
# 45-56 Delete lines 45 to 56 (can also use 56-45)
# 78- Delete line 78 to the last line
# Number ranges can be in any order in the list and can overlap.
# The lines are deleted in memory, not from the history file.
displaylines=35 # default
#displaylines= # if unset all of the history will be displayed
if [ "$1" ];then displaylines=$1;fi # or use $1 instead of default
lastline=$(echo $(history 1)) # Last line, with leading spaces removed
lastlinenum=${lastline%%[* ]*} # Extract line number from the last line
# Note: '*' after a line number in bash history indicates a modified line
# history -d$lastlinenum # Delete the command which ran this script (optional)
history $displaylines # Display history
while true;do
if [ "${displaylines//[0-9]/}" ];then break;fi # If it contains non-integer characters.
read -ep "Lines to delete (e.g. 67-89 45 103- ) or enter nothing to quit: " numbers
if ! [ "$numbers" ];then break;fi # exit if nothing entered
numbers="$numbers " # Append a space to the line number list
numbers=${numbers//- /-$lastlinenum } # e.g change '23- ' to '23-lastlinenumber '
numbers=$(echo $numbers) # Remove unnecessary spaces
# Check the entered number list is valid:
errors=$(echo "${numbers// /
}"|while read line;do
# [ "not just digits and -" OR "more than one -" OR "starts with -" ] && echo 'error'
[ "${line//[0-9-]/}" -o "${line%%*-*-*}" = '' -o "${line:0:1}" = '-' ] && echo 'error'
done)
if [ "$errors" ];then echo "Bad line number list, try again:";continue;fi
# Expand line ranges n-m to a list of individual line numbers
numbers=$(echo "${numbers// /
}" | while read line;do
if [ "${line#*-}" != "$line" ];then # Found a line containing '-' (a range 'n-m')
n=${line%-*}
m=${line#*-}
if [ $n -lt $m ];then line="$m-$n";fi # Descending order for faster reverse sorting
line="{${line/-/..}}" # Change 'n-m' to '{n..m}'
fi
eval echo $line # '{n..m}' will be expanded to a list of numbers (brace expansion)
done)
a=( $numbers ) # Put line numbers into an array for reverse unique sorting
sorted="no"
while [ "$sorted" = "no" ];do
unset sorted
for ((i=0;i<${#a[@]}-1;i++));do
if (( ${a[i]} < ${a[i+1]} ));then # Sort by comparing/swapping adjacent elements
tmp=${a[i]}
a[i]=${a[i+1]}
a[i+1]=$tmp
sorted="no"
fi
done
done
for ((i=0;i<${#a[@]}-1;i++));do # Remove duplicate line numbers from the sorted array
if (( ${a[i]} == ${a[i+1]} ));then
a[i]=
fi
done
a=( ${a[@]} ) # Remove empty array elements created by removing duplicates
i=${#a[@]} # Number of array elements
# Check that the reverse sorted list is in the range $lastlinenum to 1
if [ ${a[0]} -gt $lastlinenum -o ${a[i-1]} -lt 1 ];then
echo "Line number list is out of range, try again:"
continue
fi
echo "Deleting these lines from the above history: ${a[@]}"
echo "***********************************************************************"
for ((i=0;i<${#a[@]};i++));do
a[i]="history -d${a[i]};" # Create the delete commands e.g. history -d67; ....
done
eval ${a[@]} # Execute all the 'history -d' commands
lastline=$(echo $(history 1)) # New last line, with leading spaces removed
lastlinenum=${lastline%%[* ]*} # Extract the line number from the new last line
history $displaylines # Refresh the displayed history
done
unset a errors i lastline lastlinenum line numbers sorted tmp # Finished; tidy up
No comments:
Post a Comment