From a1990a751cc6e5f9bed598e88723ec02da1b535b Mon Sep 17 00:00:00 2001 From: druckdev <63563978+druckdev@users.noreply.github.com> Date: Mon, 26 Oct 2020 14:47:14 +0100 Subject: [PATCH] .local/bin:filterHistory: Fix bug and refactor Fix bug that `cut` only took the second field when splitting on ';' instead of everything after the first semicolon and thus not properly handling commands that contain semicolons. Add die() and hist-sort(). Use here-string instead of process substitution with input redirection. Rephrase comment. --- .local/bin/filterHistory | 44 +++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/.local/bin/filterHistory b/.local/bin/filterHistory index 824997f..c4dd9ee 100755 --- a/.local/bin/filterHistory +++ b/.local/bin/filterHistory @@ -8,25 +8,32 @@ ## format of zshs extended history. ## An automatic backup is created before deleting that can be used for recovery. -[[ $# -eq 1 ]] || { echo "Specify history file" >&2; exit 1; } -[[ -e "$1" ]] || { echo "File does not exist" >&2; exit 1; } -[[ "$(stat -c '%a' "$1")" = "600" ]] || { echo "File does not look like a history file" >&2; exit 1; } +die() { + printf "$1" >&2 + exit ${2:-1} +} -# Sort the commands per number of occurrences -most_used="$(\ - cut -d';' -f2 "$1" \ +[[ $# -eq 1 ]] || die "Specify a history file.\n" +[[ -e "$1" ]] || die "File does not exist.\n" +[[ "$(stat -c '%a' "$1")" = "600" ]] || die "File permissions are off.\n" + +# Take a history file per stdin and sort the commands per number of occurrences +hist-sort() { + cut -d';' -f2- \ | sort \ | uniq -c \ - | sort -nr \ -)" + | sort -nr +} + +most_used="$(hist-sort <"$1")" declare -a commands if command -v fzf >/dev/null 2>&1; then # Let the user pick in fzf from the most used commands - readarray -t commands < <(\ + readarray -t commands <<<"$( fzf -m --reverse --height 50% <<<"$most_used" \ - | sed -E 's/^[ \t]*[0-9]+ //' \ - ) + | sed -E 's/^[ \t]*[0-9]+ //' + )" else echo "Most used commands:" offset="$(head -1 <<<"$most_used" | sed -E 's/^( *[0-9]+).*$/\1/' | wc -m)" @@ -46,7 +53,7 @@ fi printf '%s\n' "${commands[@]}" | column -x echo "Please confirm the deletion of these commands in $1 ('yes')" read yn -[[ "$yn" = "yes" ]] || exit 1 +[[ "$yn" = "yes" ]] || die tempd="$(mktemp -d)" cp "$1" "$tempd/$(basename "$1")" @@ -55,16 +62,15 @@ echo for c in "${commands[@]}"; do # Escape all characters that sed could misinterpret. - pattern="^: [0-9]+:[0-9]+;$(sed -E 's/[./?+|()*\\^$]|\[|\]/\\&/g' <<<"$c")\$" - # Find first occurrence of the command in the history file - first="$(grep -Enm1 "$pattern" "$1" | cut -d: -f1)" + pat="^: [0-9]+:[0-9]+;$(sed -E 's/[./?+|()*\\^$]|\[|\]/\\&/g' <<<"$c")\$" + # Find line number of first occurrence of the command in the history file + first="$(grep -Enm1 "$pat" "$1" | cut -d: -f1)" - # Delete all lines beginning from the line after the first occurrence that - # contain (exactly) the command. - sed -Ei "$((first + 1)),\$ { /$pattern/d }" "$1" + # Delete all occurrences of the command except for the first one + sed -Ei "$((${first} + 1)),\$ { /$pat/d }" "$1" echo "$c deleted" done echo echo "Following commands were deleted:" -diff "$1" "$tempd/$(basename "$1")" | grep "^>" | cut -d\; -f 2 | sort | uniq -c | sort -nr +diff "$1" "$tempd/$(basename "$1")" | grep "^>" | hist-sort