.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.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user