From Mustard Mosquito, 2 Weeks ago, written in Plain Text.
  1. #!/bin/bash
  2. # Desc: Search shell history buy either, regexpr, date called, or working dir at time of call
  3. # Usage: hg [-adp] [-f FILE] [--cmd|--date|--location] REGEXP
  4. #          -a         search entire file, default is last 5000 entries
  5. #          -d         data only. print only matching table and feild. disables -p
  6. #          -f FILE    search a different file
  7. #          -p         pretty print
  8. #          +p         unpretty print
  9. #          --cmd      select cmd table as search target
  10. #          --date     select date table as search target
  11. #          --location select location table as search target
  12. #          --help     print this help message
  13. #
  14. #  Record Format                      Field Identifiers                 Field Values
  15. # ╭─────────────────────────────╮    ╭─────────────────────────────╮   ╭─────────────────────────────╮
  16. # │ ␍- cmd: to 'gawk'.␍         │ -> │\n\^ - cmd:\$\s              │ : │\s\^to 'gawk'.\$\n           │
  17. # │ ␉when: 1556828320␍          │ -> │\t\^when:\$\s                │ : │\s\^1556828320\$\n           │
  18. # │ ␉where: /home/mnrmnaugh/HWD␍│ -> │\t\^where:\$\s               │ : │\s\^/home/mnrmnaugh/HWD\$\n  │
  19. # ╰─────────────────────────────╯    ╰─────────────────────────────╯   ╰─────────────────────────────╯
  20. #
  21.  
  22.  
  23. # A function to properly format histfile. Should be called from PS1 or PROMPT_COMMAND
  24. #
  25. # histfmt(){
  26. #   histfile="$HOME"/.bash/data/HistMaster/histmaster
  27. #   history 1 | awk -v t="$(date +%s)" -v d="$(pwd)" '
  28. #     {$1=""; printf("\n- cmd:%s\n\twhen: %s\n\twhere: %s\n", $0, t, d)}' >> "$histfile"
  29. #   return $?
  30. #}
  31.  
  32.  
  33. # /* FUNCDEF */ --------------------------------------------------------------
  34. msg(){ printf -- "%s\n" "$@"; }
  35. emsg(){ printf -- "%s\n" "$@" >&2; }
  36. usage(){ awk -F '# ' 'NR>2{print $2};$0==""{exit}' <"$0"; }
  37. bail(){ emsg "$@"; usage; exit 1; }
  38.  
  39. histtok(){
  40.   # desc: print values for specified key
  41.   # usage: histtok cmd|when|where file
  42.   [[ -f "$2" ]] || return 1
  43.   [[ "$1" =~ (cmd|when|where) ]] || return 1
  44.   awk -v f="$1" -F': ' '$1~f{print $2}' <"$2"
  45. }
  46.  
  47. match(){
  48.   # desc: return matching field name and value
  49.   # usage: match regexpr file
  50.   # example: mapfile < <( match "string" "$(<./file)" )
  51.   local m
  52.   m="$1"; shift
  53.   printf -- "%s\n" "$@" \
  54.     | awk -v m="$m" '$0~m{print (NR-1)":"$0}'
  55. }
  56.  
  57. histgrep(){
  58.   # desc: create tables from histfile and perform search
  59.   # usage: histgrep pattern
  60.   declare table search file r
  61.   declare -a result index
  62.  
  63.   table="cmd"
  64.   [[ "$1" =~ (--cmd|--when|--where) ]] && table="${1#*--}" && shift 1 #while (($#)); do    case "$1" in      --cmd) table='cmd'; shift 1;;      --when) table='when'; shift 1;;      --where) table='where'; shift 1;;      *) search="$1"; file="$2"; shift 2;;    esac  done
  65.   search="$1" file="$2"
  66.   shift 2
  67.  
  68.   # Generate tables
  69.   mapfile -t cmd < <(histtok cmd "$file")
  70.   mapfile -t when < <(histtok when "$file")
  71.   mapfile -t where < <(histtok where "$file")
  72.  
  73.   # Perform search on selected table
  74.   case "$table" in
  75.     cmd) mapfile -t result < <(match "$search" "${cmd[@]}");;
  76.     when) mapfile -t result < <(match "$search" "${when[@]}");;
  77.     where) mapfile -t result < <(match "$search" "${where[@]}");;
  78.   esac
  79.  
  80.   # Clean up and align data points
  81.   for r in "${result[@]}"; do
  82.     index+=("${r%%:*}")
  83.   done
  84.  
  85.   # Print results
  86.   for r in "${index[@]}"; do
  87.     if [[ -z "$pretty" ]]; then
  88.       printf -- "- cmd: %s\n\twhen: %s\n\twhere: %s\n\n" "${cmd[$r]}" "${when[$r]}" "${where[$r]}"
  89.     else
  90.       tabsz="$(tabs -d 1|awk -F+ '$1~/^-+/{printf $1}'|wc -c)"
  91.       # NOTE: 7 is width of feild id i.e. '- cmd: '. No clue what 10 is...
  92.       let "(${#where[$r]}+7+tabsz > ${#cmd[$r]}+7+tabsz)" \
  93.         && let boxsz="(${#where[$r]}+10+tabsz)" \
  94.         || let boxsz="(${#cmd[$r]}+7+tabsz)"
  95.  
  96.       horz(){ eval printf $'\x1b\(0%c\x1b\(B' "q{1..${boxsz}"\}; }
  97.       printf -- "╭%s╮\n" "$(horz)"
  98.       #printf -- "│- cmd: %- $((boxsz-3-tabsz))s│\n│\twhen: %- $((boxsz-${#when[$r]}))s │\n│\twhere: %- $((boxsz-11))s │\n" "${cmd[$r]}" "${when[$r]}" "${where[$r]}"
  99.       printf -- "│- cmd: %- $((boxsz-3-tabsz))s│\n" "${cmd[$r]}"
  100.       printf -- "│\twhen: %- $((boxsz-${#when[$r]}))s │\n" "${when[$r]}"
  101.       printf -- "│\twhere: %- $((boxsz-11))s │\n" "${where[$r]}"
  102.       printf -- "╰%s╯\n" "$(horz)"
  103.     fi
  104.   done
  105. }
  106.  
  107. # /* ENV */ ------------------------------------------------------------------
  108. declare pattern file defaultfile tmp table pretty allscan dataonly
  109. pretty='true'
  110. defaultfile="$HOME/.bash/data/HistMaster/histmaster"
  111. table='--cmd'
  112.  
  113.  
  114. # /* INIT */ -----------------------------------------------------------------
  115. trap 'rm "$tmp" 2<&-' EXIT
  116. [[ -z "$1" ]] && bail "E!: search pattern required"
  117.  
  118.  
  119. # /* MAIN */ -----------------------------------------------------------------
  120. while (($#)); do
  121.   case "$1" in
  122.     --help) usage; exit 0;;
  123.     -p) pretty='true'; shift; continue;;
  124.     +p) pretty=''; shift; continue;;
  125.     -d) dataonly='true'; shift; continue;;
  126.     -f) [[ -r "$2" ]] || bail "E:! file not found"
  127.         file="${file:-$2}"; shift 2; continue;;
  128.     -a) allscan='true'; file="${file:-$defaultfile}"; shift; continue;;
  129.     --cmd) table="--cmd"; shift;;
  130.     --when|--date) table="--when"; shift;;
  131.     --where|--loc*) table="--where"; shift;;
  132.     *) [[ ! -r "$tmp" && ! "$allscan" == "true" ]] \
  133.          && tmp="./$(mktemp -u tmp.XXXXXXXXXX)" \
  134.          && tail -n 20000 "${file:-$defaultfile}" >"$tmp"
  135.       pattern="${pattern:-$1}" file="${file:-$tmp}"; shift; continue;;
  136.   esac
  137. done
  138.  
  139. if [[ -z "$dataonly" ]]; then
  140.   [[ -z "$pretty" ]] \
  141.   && histgrep "$table" "$pattern" "$file" \
  142.   || histgrep "$table" "$pattern" "$file" \
  143.     | awk -v pat="$pattern" '
  144.       {gsub(pat, "\x1b[1;97m&\x1b[0m", $0)}
  145.       {gsub(/(╭|╰)/, "\x1b[95m&", $0)}
  146.       {gsub(/│/, "│\x1b[92m", $0)}
  147.       {gsub(/│\x1b\[92m(\twh.*: |- cmd: )/, "&\x1b[0m", $0)}
  148.       {gsub(/│/, "\x1b[95m│", $0)}
  149.       {print $0}
  150.       '
  151. else
  152.   histgrep "$table" "$pattern" "$file" \
  153.     | awk -v tbl="$table" -F':' '$0~tbl{print $2}'
  154. fi
  155.  
  156.  
  157. #alias hg='HistGrep'
  158. #alias hist='printf -- "no! \`hg\` for HistGrep">&2'
  159. #HistGrep(){
  160. #  usage(){ printf -- "usage: $FUNCNAME QUERY\n"; }
  161. #  bail(){ printf -- "%s\n" "$@" >&2; usage; }
  162. #  [[ -n "$1" ]] || { bail "E!: missing arg"; return 1; }
  163. #  [[ "$1" =~ -(h|-help) ]] && usage && return 0
  164. #
  165. #  #builtin mapfile -t hf < <(command find ~/.bash/data/HistMaster/histmaster* -type f | sort -r)
  166. #  for f in ~/.bash/data/HistMaster/histmaster*; do
  167. #    builtin mapfile -t hf < <(printf -- "%s\n%s\n" "${f}" "${hf[@]}")
  168. #  done
  169. #
  170. #  ∂(){ command gawk -v q="$1" -e '
  171. #    BEGIN{ORS="";RS="- cmd:";FS=RS".*$"}
  172. #      {if($1~q) print RS $0}' "${hf[@]}"
  173. #  }
  174. #
  175. #  command gawk 'BEGIN{exit}' 2<&- 1<&- \
  176. #    && ƒ(){ ∂ "$1"; } \
  177. #    || ƒ(){ command grep -A 3 "$1"; }
  178. #
  179. #    ƒ "$1" | cat -v
  180. #}
captcha