random bash scripts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
4.3 KiB

  1. #!/usr/bin/env bash
  2. declare -a counts freq cmds filters
  3. line_len=$(($(/usr/bin/tput cols) - 2)) # get terminal width
  4. num_entries=15
  5. chart_char='='
  6. OPTIND=1 # reset getopts
  7. max_len=0
  8. ppid=$PPID
  9. zsh_extended_filter_string="^:[0-9 ]*:[0-9];"
  10. fish_filter_string="^\\- cmd: "
  11. sudo_filter_string="^sudo "
  12. # define colors
  13. source ./colors.sh
  14. color1=$lcyan
  15. color2=$lpurple
  16. function debug() {
  17. echo "commit: $(git rev-parse HEAD)"
  18. echo "uname: $(uname -a)"
  19. get_shell
  20. echo "shell: $shell"
  21. get_history_file
  22. echo "histfile: $histfile"
  23. }
  24. function show_help() {
  25. echo "usage: $0 [-h] [-d] [-n entries] [-f hist_file] [-c chart_char] [-l line_len]"
  26. }
  27. function err() {
  28. echo "$1"
  29. exit 1
  30. }
  31. function separator() {
  32. for (( n=0; n<=line_len; n++ ))
  33. do
  34. # shellcheck disable=SC2059
  35. printf "$white-$nocolor"
  36. done
  37. printf "\\n"
  38. }
  39. # generic shell formatting filter
  40. function shell_filter() {
  41. if grep -E "$2" <<< "$1" >/dev/null; then
  42. grep -E "$2" <<< "$1" \
  43. | sed -e "s/$2//g"
  44. else
  45. echo "$1"
  46. fi
  47. }
  48. # if match fish history format, remove fish formating
  49. function fish_filter() {
  50. shell_filter "$1" "$fish_filter_string"
  51. }
  52. # if match zsh_extended history format, remove zsh_extended formating
  53. function zsh_extended_filter() {
  54. shell_filter "$1" "$zsh_extended_filter_string"
  55. }
  56. # remove 'sudo's
  57. function sudo_filter() {
  58. sed -e "s/$sudo_filter_string//g" <<< "$1"
  59. }
  60. # get command name, sort, and count
  61. function final_filter() {
  62. awk '{print $1}' <<< "$1" \
  63. | sort \
  64. | uniq -c \
  65. | sort -rn
  66. }
  67. # check the shell used to instantiate ginh
  68. function get_shell() {
  69. shell=$(ps -p "$ppid" -o comm= | sed -e 's/^-//')
  70. if [ -z "$shell" ]; then
  71. err "unable to autodetect shell, try specifying a file using -f"
  72. fi
  73. }
  74. # get location of history file for the shell used to instantiate ginh
  75. function get_history_file() {
  76. get_shell
  77. if [ "$shell" == "fish" ]; then
  78. # fish history cannot be changed, determine location based on version
  79. fish_version="$(fish -v | awk '{print $3}')"
  80. if version_gt "$fish_version" "2.3.0"; then
  81. histfile="$HOME/.local/share/fish/fish_history"
  82. else
  83. histfile="$HOME/.config/fish/fish_history"
  84. fi
  85. else
  86. histfile=$("$shell" -ci "echo \$HISTFILE")
  87. fi
  88. if [ -z "$histfile" ]; then
  89. err "unable to autodetect history file, try specifying a file using -f"
  90. fi
  91. }
  92. # test if the first argument is greater than the second argument,
  93. # following versioning logic
  94. function version_gt() {
  95. test "$(sort -V <<< "$@" | head -n 1)" != "$1"
  96. }
  97. while getopts "h?dn:f:c:l:t:" opt; do
  98. case "$opt" in
  99. h|\?)
  100. show_help
  101. exit 0
  102. ;;
  103. d)
  104. debug
  105. exit 0
  106. ;;
  107. n)
  108. num_entries=$OPTARG
  109. ;;
  110. f)
  111. histfile=$OPTARG
  112. ;;
  113. c)
  114. chart_char="$OPTARG"
  115. ;;
  116. l)
  117. line_len=$OPTARG
  118. ;;
  119. t)
  120. ppid=$OPTARG
  121. ;;
  122. esac
  123. done
  124. shift $((OPTIND-1))
  125. [ "${1:-}" = "--" ] && shift
  126. if [ -z "$histfile" ]; then
  127. get_history_file
  128. fi
  129. filters+=("fish_filter")
  130. filters+=("zsh_extended_filter")
  131. filters+=("sudo_filter")
  132. filters+=("final_filter")
  133. calc=$(grep -v -E '^\s*$|^\s+' "$histfile")
  134. for (( n=0; n<${#filters[@]}; n++ )); do
  135. calc=$("${filters[n]}" "$calc")
  136. done
  137. # choose smaller of requested number of entries and actual number
  138. num_lines=$(wc -l <<< "$calc")
  139. num_entries=$((num_lines < num_entries
  140. ? num_lines
  141. : num_entries))
  142. echo "entries=$num_entries, file=$histfile, char=$chart_char, len=$line_len"
  143. for (( n=0; n<num_entries; n++ )); do
  144. # gather counts and cmds
  145. cmds[n]="$(sed -ne "$((1 + n))p" <<< "$calc")" # isolate line n+1
  146. counts[n]="$(awk '{print $1}' <<< "${cmds[n]}")"
  147. s=$(awk '{print $2}' <<< "${cmds[n]}")
  148. max_len=$((
  149. ${#s} > max_len
  150. ? ${#s}
  151. : max_len
  152. ))
  153. done
  154. max_len=$((max_len + 1))
  155. for (( n=0; n<num_entries; n++ )); do
  156. # calculate frequencies
  157. (( freq[n]=counts[n] * \
  158. $((line_len - max_len - ${#counts[0]} - 2)) \
  159. / counts[0] ))
  160. done
  161. separator
  162. for (( n=0; n<num_entries; n++ )); do
  163. if [[ $((n % 2)) == 0 ]]; then
  164. color=$color1
  165. else
  166. color=$color2
  167. fi
  168. s=$(awk '{print $2}' <<< "${cmds[n]}")
  169. for (( m=0; m<=max_len-${#s} - 2; m++ )); do
  170. printf " "
  171. done
  172. printf "$color%s$nocolor " "$(awk '{print $2}' <<< "${cmds[n]}")"
  173. for (( m=0; m<=freq[n]; m++ )); do
  174. printf "$color%s$nocolor" "$chart_char"
  175. done
  176. printf " "
  177. printf "$color%s$nocolor" "${counts[n]}"
  178. printf "\\n"
  179. done
  180. separator